gloomberb 0.18.4 → 0.19.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 (600) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/package.json +1 -1
  4. package/patches/electrobun@1.18.1.patch +169 -5
  5. package/src/account/auth-model.ts +7 -3
  6. package/src/api-client/auth.ts +9 -4
  7. package/src/api-client/catalysts.ts +2 -1
  8. package/src/api-client/cot.ts +6 -2
  9. package/src/api-client/credit-documents.ts +6 -0
  10. package/src/api-client/data.ts +31 -6
  11. package/src/api-client/equity-screener.ts +24 -0
  12. package/src/api-client/fund-facts.ts +45 -4
  13. package/src/api-client/index.ts +171 -11
  14. package/src/api-client/live-scan.ts +91 -0
  15. package/src/api-client/market-discovery.ts +10 -0
  16. package/src/api-client/market-movers.ts +7 -0
  17. package/src/api-client/members.ts +13 -1
  18. package/src/api-client/perps.ts +43 -0
  19. package/src/api-client/request.ts +222 -41
  20. package/src/api-client/research-activity.ts +6 -12
  21. package/src/api-client/types.ts +74 -0
  22. package/src/app/keybindings/index.ts +3 -0
  23. package/src/app/keybindings/labels.ts +18 -1
  24. package/src/app/keybindings/resolve.ts +14 -0
  25. package/src/app/pane-runtime/plugin-bindings.ts +9 -5
  26. package/src/app/runtime/broker-import.ts +42 -27
  27. package/src/app/runtime/plugin-bindings.ts +73 -56
  28. package/src/architecture/core-builtin-allowlist.json +1 -1
  29. package/src/architecture/pane-tabs-allowlist.json +3 -0
  30. package/src/architecture/ttl-caches-allowlist.json +19 -0
  31. package/src/brokers/sync-broker-instance.ts +2 -8
  32. package/src/capabilities/chart-series.ts +1 -1
  33. package/src/cli/commands/crypto-hints.ts +40 -24
  34. package/src/cli/commands/fred-series.ts +5 -0
  35. package/src/cli/commands/keybindings.ts +23 -0
  36. package/src/cli/commands/market.ts +138 -46
  37. package/src/cli/commands/options-chain.ts +107 -10
  38. package/src/cli/commands/options-leaps.ts +9 -3
  39. package/src/cli/commands/overview.ts +176 -39
  40. package/src/cli/commands/search.ts +39 -3
  41. package/src/cli/commands/themes.ts +11 -2
  42. package/src/cli/commands/ticker.ts +57 -35
  43. package/src/cli/company-name-hint.ts +41 -0
  44. package/src/cli/earnings-calendar.ts +1 -1
  45. package/src/cli/errors.ts +10 -2
  46. package/src/cli/export-source.ts +29 -1
  47. package/src/cli/glossary.ts +73 -1
  48. package/src/cli/history-rows.ts +87 -16
  49. package/src/cli/index.ts +2 -0
  50. package/src/cli/known-gaps.ts +5 -2
  51. package/src/cli/listing-arg.ts +195 -56
  52. package/src/cli/output-file.ts +68 -0
  53. package/src/cli/pane-functions/capabilities.ts +3 -0
  54. package/src/cli/pane-functions/catalog.ts +80 -7
  55. package/src/cli/pane-functions/dom.ts +13 -3
  56. package/src/cli/pane-functions/freshness.ts +111 -16
  57. package/src/cli/pane-functions/function-help.ts +23 -13
  58. package/src/cli/pane-functions/headless.ts +56 -12
  59. package/src/cli/pane-functions/index.ts +58 -16
  60. package/src/cli/pane-functions/market-session.ts +81 -9
  61. package/src/cli/pane-functions/options.ts +19 -1
  62. package/src/cli/pane-functions/report.ts +5 -1
  63. package/src/cli/pane-functions/resolver.ts +35 -8
  64. package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
  65. package/src/cli/pane-functions/screenshot-types.ts +5 -0
  66. package/src/cli/quote-answer.ts +30 -13
  67. package/src/cli/report-tables.ts +18 -7
  68. package/src/cli/restore-plugins.ts +13 -1
  69. package/src/cli/result.ts +57 -5
  70. package/src/cli/ticker-resolution.ts +3 -2
  71. package/src/components/chart/composite/composite-chart.tsx +26 -4
  72. package/src/components/chart/composite/format.ts +27 -0
  73. package/src/components/chart/composite/interactions.ts +6 -0
  74. package/src/components/chart/composite/legend.tsx +45 -7
  75. package/src/components/chart/composite/levels.ts +2 -0
  76. package/src/components/chart/composite/panel-gestures.ts +33 -0
  77. package/src/components/chart/composite/panel-series.ts +1 -0
  78. package/src/components/chart/composite/panel-surface.tsx +61 -5
  79. package/src/components/chart/composite/range-statistics.ts +62 -0
  80. package/src/components/chart/composite/rasterizer.ts +24 -13
  81. package/src/components/chart/composite/scene.ts +46 -7
  82. package/src/components/chart/composite/series-axis-tags.tsx +16 -9
  83. package/src/components/chart/composite/series-cues.ts +14 -0
  84. package/src/components/chart/composite/text-renderer.ts +9 -2
  85. package/src/components/chart/composite/tool-catalog.ts +36 -0
  86. package/src/components/chart/composite/tools.ts +203 -44
  87. package/src/components/chart/composite/types.ts +4 -0
  88. package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
  89. package/src/components/command-bar/assist/inventory.ts +2 -1
  90. package/src/components/command-bar/commands/direct/index.ts +28 -13
  91. package/src/components/command-bar/pane-templates/items.ts +3 -2
  92. package/src/components/command-bar/panel/prompt-binding.ts +0 -8
  93. package/src/components/command-bar/workflow/alert.ts +1 -1
  94. package/src/components/command-bar/workflow/collection-actions.ts +3 -3
  95. package/src/components/layout/header.tsx +26 -40
  96. package/src/components/layout/pane/footer/index.tsx +1 -0
  97. package/src/components/layout/pane/footer/model.ts +27 -0
  98. package/src/components/onboarding/onboarding-frame.tsx +1 -1
  99. package/src/components/onboarding/onboarding-wizard.tsx +4 -1
  100. package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -9
  101. package/src/components/onboarding/wizard-broker-sync.ts +0 -1
  102. package/src/components/onboarding/wizard-positions.ts +3 -3
  103. package/src/components/ticker/list-table-view.tsx +4 -1
  104. package/src/components/ui/choice-dialog.tsx +23 -18
  105. package/src/components/ui/choice-groups.ts +18 -0
  106. package/src/components/ui/data-table/opentui/index.tsx +9 -7
  107. package/src/components/ui/data-table/opentui/model.ts +26 -1
  108. package/src/components/ui/data-table/types.ts +2 -0
  109. package/src/components/ui/display.tsx +5 -1
  110. package/src/components/ui/list-view.tsx +8 -4
  111. package/src/components/ui/query-bar-keys.tsx +2 -0
  112. package/src/components/ui/query-bar.tsx +1 -0
  113. package/src/components/ui/select-button.tsx +5 -1
  114. package/src/components/ui/select-field.tsx +1 -0
  115. package/src/components/ui/table-layout.ts +8 -5
  116. package/src/core/app-runtime.ts +2 -0
  117. package/src/core/app-services.ts +2 -2
  118. package/src/core/state/app/layout.ts +2 -0
  119. package/src/core/state/app/state.ts +9 -0
  120. package/src/core/state/app/types.ts +3 -0
  121. package/src/data/config/chart-settings.ts +1 -1
  122. package/src/data/json-ticker-repository.ts +17 -8
  123. package/src/data/saved-copies.ts +55 -16
  124. package/src/data/ticker-repository.ts +16 -9
  125. package/src/data/ticker-writes.ts +81 -0
  126. package/src/data/ttl-cache.ts +165 -0
  127. package/src/docs/snapshot.json +427 -216
  128. package/src/i18n/es.ts +19 -3
  129. package/src/i18n/ja.ts +19 -3
  130. package/src/i18n/ko.ts +19 -3
  131. package/src/i18n/zh-cn.ts +19 -3
  132. package/src/i18n/zh-tw.ts +19 -3
  133. package/src/market-data/coordinator/financials.ts +10 -2
  134. package/src/market-data/coordinator/index.ts +3 -1
  135. package/src/market-data/coordinator/quotes.ts +4 -2
  136. package/src/market-data/depositary-pair.ts +2 -2
  137. package/src/market-data/fund-facts.ts +50 -0
  138. package/src/market-data/market/change-basis.ts +48 -7
  139. package/src/market-data/market/dated-previous-close.ts +203 -0
  140. package/src/market-data/market/format.ts +25 -0
  141. package/src/market-data/market/freshness.ts +2 -1
  142. package/src/market-data/market/futures-week.ts +68 -0
  143. package/src/market-data/market/status.ts +16 -4
  144. package/src/market-data/options-alternatives.ts +141 -4
  145. package/src/market-data/quotes/contributions.ts +20 -2
  146. package/src/market-data/quotes/resolution.ts +3 -0
  147. package/src/market-data/selectors.ts +3 -0
  148. package/src/news/aggregator.ts +113 -9
  149. package/src/news/cloud-session.ts +21 -0
  150. package/src/news/hooks.ts +1 -0
  151. package/src/news/news-model.ts +1 -0
  152. package/src/news/types.ts +11 -0
  153. package/src/notifications/notification-log.ts +6 -4
  154. package/src/plugins/builtin/alerts/alert-engine.ts +25 -2
  155. package/src/plugins/builtin/alerts/alert-log.ts +33 -0
  156. package/src/plugins/builtin/alerts/calendar-events.ts +57 -6
  157. package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
  158. package/src/plugins/builtin/alerts/cli.ts +380 -82
  159. package/src/plugins/builtin/alerts/command.ts +31 -0
  160. package/src/plugins/builtin/alerts/constants.ts +1 -1
  161. package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
  162. package/src/plugins/builtin/alerts/fired-log.ts +113 -8
  163. package/src/plugins/builtin/alerts/format.ts +80 -4
  164. package/src/plugins/builtin/alerts/headless.ts +30 -7
  165. package/src/plugins/builtin/alerts/history-rows.ts +7 -3
  166. package/src/plugins/builtin/alerts/history.ts +2 -0
  167. package/src/plugins/builtin/alerts/index.tsx +135 -22
  168. package/src/plugins/builtin/alerts/live.ts +3 -3
  169. package/src/plugins/builtin/alerts/metric-command.ts +134 -0
  170. package/src/plugins/builtin/alerts/metric-data.ts +111 -0
  171. package/src/plugins/builtin/alerts/metric-model.ts +324 -0
  172. package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
  173. package/src/plugins/builtin/alerts/pane.tsx +90 -39
  174. package/src/plugins/builtin/alerts/quotes.ts +6 -0
  175. package/src/plugins/builtin/alerts/storage.ts +37 -10
  176. package/src/plugins/builtin/alerts/types.ts +7 -0
  177. package/src/plugins/builtin/analytics/index.tsx +2 -1
  178. package/src/plugins/builtin/analytics/risk-client.ts +16 -5
  179. package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
  180. package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
  181. package/src/plugins/builtin/analytics/risk-model.ts +55 -9
  182. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
  183. package/src/plugins/builtin/attention/index.tsx +2 -1
  184. package/src/plugins/builtin/attention/listing.ts +14 -0
  185. package/src/plugins/builtin/backtest/headless.ts +10 -5
  186. package/src/plugins/builtin/backtest/pane.tsx +9 -4
  187. package/src/plugins/builtin/backtest/presets.ts +29 -3
  188. package/src/plugins/builtin/broker-manager/index.tsx +10 -5
  189. package/src/plugins/builtin/broker-manager/model.ts +6 -1
  190. package/src/plugins/builtin/broker-trading/controller.ts +22 -12
  191. package/src/plugins/builtin/broker-trading/index.tsx +13 -1
  192. package/src/plugins/builtin/broker-trading/order-feed.ts +9 -4
  193. package/src/plugins/builtin/broker-trading/pane.tsx +1 -1
  194. package/src/plugins/builtin/buildout/cells.tsx +12 -4
  195. package/src/plugins/builtin/buildout/format.ts +38 -0
  196. package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
  197. package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
  198. package/src/plugins/builtin/buildout/table-model.ts +23 -2
  199. package/src/plugins/builtin/builtin-plugin-meta.ts +7 -3
  200. package/src/plugins/builtin/catalysts/model.ts +2 -1
  201. package/src/plugins/builtin/changelog/index.tsx +9 -6
  202. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +6 -1
  203. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +1 -1
  204. package/src/plugins/builtin/chart-composer/cli-options.ts +9 -5
  205. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +12 -2
  206. package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -2
  207. package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
  208. package/src/plugins/builtin/chart-composer/editor.tsx +7 -5
  209. package/src/plugins/builtin/chart-composer/formula.ts +71 -18
  210. package/src/plugins/builtin/chart-composer/headless-schema.ts +21 -4
  211. package/src/plugins/builtin/chart-composer/headless.ts +19 -3
  212. package/src/plugins/builtin/chart-composer/index.tsx +1 -1
  213. package/src/plugins/builtin/chart-composer/pane.tsx +53 -9
  214. package/src/plugins/builtin/chart-composer/presets.ts +50 -15
  215. package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
  216. package/src/plugins/builtin/chart-composer/session-history.ts +18 -9
  217. package/src/plugins/builtin/chart-composer/settings.ts +27 -0
  218. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +40 -26
  219. package/src/plugins/builtin/chat/content/command-suggestions.ts +93 -0
  220. package/src/plugins/builtin/chat/content/composer.tsx +13 -6
  221. package/src/plugins/builtin/chat/content/footer.tsx +6 -3
  222. package/src/plugins/builtin/chat/content/index.tsx +50 -21
  223. package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
  224. package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
  225. package/src/plugins/builtin/chat/index.tsx +23 -0
  226. package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
  227. package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
  228. package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
  229. package/src/plugins/builtin/chat/pane-links/commands.ts +271 -0
  230. package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
  231. package/src/plugins/builtin/chat/pane-links/open.ts +8 -1
  232. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
  233. package/src/plugins/builtin/clinical-trials/model.ts +0 -9
  234. package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
  235. package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
  236. package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
  237. package/src/plugins/builtin/cloud/plugin.tsx +1 -1
  238. package/src/plugins/builtin/company-attention/building.tsx +5 -1
  239. package/src/plugins/builtin/company-attention/client.ts +8 -9
  240. package/src/plugins/builtin/company-attention/evidence.ts +4 -1
  241. package/src/plugins/builtin/company-attention/moves.tsx +5 -1
  242. package/src/plugins/builtin/company-attention/pane.tsx +9 -2
  243. package/src/plugins/builtin/company-attention/signals.tsx +5 -1
  244. package/src/plugins/builtin/correlation/headless.ts +13 -5
  245. package/src/plugins/builtin/correlation/history.ts +22 -0
  246. package/src/plugins/builtin/cot/client.ts +22 -18
  247. package/src/plugins/builtin/cot/headless.ts +15 -10
  248. package/src/plugins/builtin/cot/model.ts +14 -1
  249. package/src/plugins/builtin/cot/pane.tsx +22 -14
  250. package/src/plugins/builtin/credit-boards/client.ts +6 -10
  251. package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
  252. package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
  253. package/src/plugins/builtin/credit-conditions/model.ts +4 -0
  254. package/src/plugins/builtin/credit-conditions/series.ts +3 -1
  255. package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
  256. package/src/plugins/builtin/credit-documents/export.ts +173 -0
  257. package/src/plugins/builtin/credit-documents/headless.ts +7 -7
  258. package/src/plugins/builtin/credit-documents/model.ts +104 -14
  259. package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
  260. package/src/plugins/builtin/custom-view/sources.ts +2 -0
  261. package/src/plugins/builtin/dividend-yield/client.ts +131 -23
  262. package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
  263. package/src/plugins/builtin/dividend-yield/model.ts +8 -5
  264. package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
  265. package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
  266. package/src/plugins/builtin/dividend-yield/types.ts +20 -2
  267. package/src/plugins/builtin/dividend-yield/view.ts +30 -2
  268. package/src/plugins/builtin/docs/targets.ts +5 -1
  269. package/src/plugins/builtin/earnings/board-model.ts +16 -15
  270. package/src/plugins/builtin/earnings/board.tsx +62 -71
  271. package/src/plugins/builtin/earnings/headless.ts +40 -4
  272. package/src/plugins/builtin/earnings/scope.ts +31 -43
  273. package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
  274. package/src/plugins/builtin/earnings-calls/format.ts +31 -2
  275. package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
  276. package/src/plugins/builtin/earnings-calls/model.ts +6 -1
  277. package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
  278. package/src/plugins/builtin/econ/calendar-model.ts +14 -9
  279. package/src/plugins/builtin/econ/figures.ts +72 -0
  280. package/src/plugins/builtin/econ/index.tsx +33 -3
  281. package/src/plugins/builtin/econ/types.ts +4 -0
  282. package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
  283. package/src/plugins/builtin/econ-statistics/headless.ts +85 -35
  284. package/src/plugins/builtin/econ-statistics/stats.ts +37 -9
  285. package/src/plugins/builtin/econ-statistics/view.ts +3 -0
  286. package/src/plugins/builtin/equity-screener/categories.ts +179 -0
  287. package/src/plugins/builtin/equity-screener/client.ts +4 -2
  288. package/src/plugins/builtin/equity-screener/headless.ts +144 -13
  289. package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
  290. package/src/plugins/builtin/equity-screener/model.ts +99 -10
  291. package/src/plugins/builtin/equity-screener/pane.tsx +70 -15
  292. package/src/plugins/builtin/exposure/charts.tsx +2 -2
  293. package/src/plugins/builtin/exposure/model.ts +13 -1
  294. package/src/plugins/builtin/exposure/pane.tsx +4 -4
  295. package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
  296. package/src/plugins/builtin/futures/index.tsx +1 -0
  297. package/src/plugins/builtin/futures/model.ts +2 -1
  298. package/src/plugins/builtin/futures/table.tsx +2 -2
  299. package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
  300. package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
  301. package/src/plugins/builtin/fx-matrix/client.ts +11 -3
  302. package/src/plugins/builtin/fx-matrix/headless.ts +6 -3
  303. package/src/plugins/builtin/fx-matrix/index.tsx +16 -4
  304. package/src/plugins/builtin/fx-matrix/live-legs.ts +54 -3
  305. package/src/plugins/builtin/gpu/headless.ts +8 -2
  306. package/src/plugins/builtin/help/function-index.ts +4 -1
  307. package/src/plugins/builtin/help/index.tsx +1 -0
  308. package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
  309. package/src/plugins/builtin/help/shortcut-model.ts +1 -1
  310. package/src/plugins/builtin/holders/fund-holders.ts +51 -0
  311. package/src/plugins/builtin/holders/headless.ts +18 -1
  312. package/src/plugins/builtin/iv-history/client.ts +52 -11
  313. package/src/plugins/builtin/iv-history/format.ts +36 -23
  314. package/src/plugins/builtin/iv-history/headless.ts +36 -18
  315. package/src/plugins/builtin/iv-history/index.tsx +2 -2
  316. package/src/plugins/builtin/iv-history/model.ts +163 -27
  317. package/src/plugins/builtin/iv-history/pane.tsx +10 -6
  318. package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
  319. package/src/plugins/builtin/iv-history/universe.ts +5 -1
  320. package/src/plugins/builtin/jobs/client.ts +25 -29
  321. package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
  322. package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
  323. package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
  324. package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
  325. package/src/plugins/builtin/macro-day/pane.tsx +7 -5
  326. package/src/plugins/builtin/macro-day/release-table.ts +2 -2
  327. package/src/plugins/builtin/market-heatmap/data.ts +8 -33
  328. package/src/plugins/builtin/market-movers/client.ts +25 -7
  329. package/src/plugins/builtin/market-movers/footer.ts +2 -2
  330. package/src/plugins/builtin/market-movers/headless.ts +32 -12
  331. package/src/plugins/builtin/market-movers/index.tsx +26 -14
  332. package/src/plugins/builtin/market-movers/min-float.ts +74 -0
  333. package/src/plugins/builtin/market-movers/model.ts +4 -1
  334. package/src/plugins/builtin/market-movers/screener.ts +14 -0
  335. package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
  336. package/src/plugins/builtin/market-movers/session-table.ts +4 -3
  337. package/src/plugins/builtin/market-movers/table.ts +17 -5
  338. package/src/plugins/builtin/members/breadth-pane.tsx +82 -0
  339. package/src/plugins/builtin/members/client.ts +19 -4
  340. package/src/plugins/builtin/members/headless.ts +20 -7
  341. package/src/plugins/builtin/members/index.tsx +9 -9
  342. package/src/plugins/builtin/members/model.ts +23 -4
  343. package/src/plugins/builtin/members/pane.tsx +25 -15
  344. package/src/plugins/builtin/news/index.tsx +1 -0
  345. package/src/plugins/builtin/news/wire/categories.ts +19 -3
  346. package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
  347. package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
  348. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
  349. package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
  350. package/src/plugins/builtin/openfda/client.ts +14 -2
  351. package/src/plugins/builtin/openfda/index.tsx +3 -2
  352. package/src/plugins/builtin/openfda/model.ts +9 -0
  353. package/src/plugins/builtin/openfda/pane.tsx +42 -6
  354. package/src/plugins/builtin/options/analytics.ts +54 -6
  355. package/src/plugins/builtin/options/enrichment.ts +17 -5
  356. package/src/plugins/builtin/options/model-spot.ts +5 -2
  357. package/src/plugins/builtin/options/strike-window.ts +2 -1
  358. package/src/plugins/builtin/options/table.ts +6 -9
  359. package/src/plugins/builtin/options/types.ts +2 -0
  360. package/src/plugins/builtin/options/view.tsx +42 -12
  361. package/src/plugins/builtin/options-positioning/client.ts +30 -0
  362. package/src/plugins/builtin/options-positioning/headless.ts +74 -21
  363. package/src/plugins/builtin/options-positioning/index.tsx +4 -4
  364. package/src/plugins/builtin/options-positioning/model.ts +122 -14
  365. package/src/plugins/builtin/options-positioning/pane.tsx +87 -42
  366. package/src/plugins/builtin/options-scenario/client.ts +116 -47
  367. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
  368. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
  369. package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
  370. package/src/plugins/builtin/options-scenario/csp.ts +8 -2
  371. package/src/plugins/builtin/options-scenario/index.tsx +9 -7
  372. package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
  373. package/src/plugins/builtin/pe-band/model.ts +12 -49
  374. package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
  375. package/src/plugins/builtin/perps/cascade.ts +236 -0
  376. package/src/plugins/builtin/perps/client.ts +56 -2
  377. package/src/plugins/builtin/perps/freshness.ts +12 -10
  378. package/src/plugins/builtin/perps/headless.ts +65 -9
  379. package/src/plugins/builtin/perps/index.tsx +7 -5
  380. package/src/plugins/builtin/perps/live-rows.ts +10 -3
  381. package/src/plugins/builtin/perps/model.ts +18 -4
  382. package/src/plugins/builtin/perps/pane.tsx +32 -31
  383. package/src/plugins/builtin/perps/status-line.ts +25 -0
  384. package/src/plugins/builtin/plugin-module.ts +5 -1
  385. package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
  386. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
  387. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
  388. package/src/plugins/builtin/portfolio-list/cli/render.ts +12 -7
  389. package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
  390. package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
  391. package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
  392. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
  393. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
  394. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +3 -1
  395. package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
  396. package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
  397. package/src/plugins/builtin/primary-dealers/client.ts +13 -38
  398. package/src/plugins/builtin/rate-path/pane.tsx +2 -2
  399. package/src/plugins/builtin/realized-vol/index.tsx +2 -2
  400. package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
  401. package/src/plugins/builtin/relative-rotation/client.ts +18 -4
  402. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  403. package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
  404. package/src/plugins/builtin/relative-rotation/model.ts +16 -40
  405. package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
  406. package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
  407. package/src/plugins/builtin/research/event-model.ts +10 -8
  408. package/src/plugins/builtin/research/headless.ts +1 -1
  409. package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
  410. package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
  411. package/src/plugins/builtin/research/relative-valuation-pane.tsx +11 -9
  412. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
  413. package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
  414. package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
  415. package/src/plugins/builtin/scanner/feed.ts +2 -2
  416. package/src/plugins/builtin/scanner/flow-model.ts +50 -4
  417. package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
  418. package/src/plugins/builtin/scanner/flow-session.ts +146 -0
  419. package/src/plugins/builtin/scanner/headless.ts +204 -35
  420. package/src/plugins/builtin/scanner/index.ts +40 -6
  421. package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
  422. package/src/plugins/builtin/scanner/live-feed.ts +168 -0
  423. package/src/plugins/builtin/scanner/live-headless.ts +138 -0
  424. package/src/plugins/builtin/scanner/live-model.ts +362 -0
  425. package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
  426. package/src/plugins/builtin/scanner/live-track.ts +186 -0
  427. package/src/plugins/builtin/scanner/lock-note.ts +3 -2
  428. package/src/plugins/builtin/seasonality/headless.ts +10 -1
  429. package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
  430. package/src/plugins/builtin/sec/fund-facts.ts +116 -34
  431. package/src/plugins/builtin/sec/headless.ts +2 -1
  432. package/src/plugins/builtin/series-inventory.ts +3 -0
  433. package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
  434. package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
  435. package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
  436. package/src/plugins/builtin/shared/earnings-report.ts +2 -2
  437. package/src/plugins/builtin/shared/job-posting.ts +1 -0
  438. package/src/plugins/builtin/shared/macro-releases.ts +65 -0
  439. package/src/plugins/builtin/shared/members-menu.tsx +3 -2
  440. package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
  441. package/src/plugins/builtin/shared/report-freshness.ts +3 -2
  442. package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
  443. package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
  444. package/src/plugins/builtin/shared/ticker-company.ts +77 -0
  445. package/src/plugins/builtin/shared/use-quote-board.ts +10 -3
  446. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
  447. package/src/plugins/builtin/shared/volatility/pricing.ts +26 -1
  448. package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
  449. package/src/plugins/builtin/themes/headless.ts +6 -4
  450. package/src/plugins/builtin/themes/model.ts +17 -8
  451. package/src/plugins/builtin/themes/pane.tsx +7 -7
  452. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
  453. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
  454. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
  455. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
  456. package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
  457. package/src/plugins/builtin/ticker-detail/overview/model.ts +1 -1
  458. package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
  459. package/src/plugins/builtin/ticker-detail/quote-footer.ts +6 -1
  460. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
  461. package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
  462. package/src/plugins/builtin/time-sales/pane.tsx +31 -19
  463. package/src/plugins/builtin/treasury-daily/client.ts +41 -5
  464. package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
  465. package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
  466. package/src/plugins/builtin/treasury-daily/model.ts +50 -3
  467. package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
  468. package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
  469. package/src/plugins/builtin/vol-surface/client.ts +9 -17
  470. package/src/plugins/builtin/vol-surface/headless.ts +63 -14
  471. package/src/plugins/builtin/vol-surface/index.tsx +2 -2
  472. package/src/plugins/builtin/vol-surface/model.ts +22 -7
  473. package/src/plugins/builtin/vol-surface/pane.tsx +48 -9
  474. package/src/plugins/builtin/vol-surface/tables.ts +31 -3
  475. package/src/plugins/builtin/volatility/dvol.ts +46 -0
  476. package/src/plugins/builtin/volatility/index.tsx +2 -2
  477. package/src/plugins/builtin/volatility/pane.tsx +4 -4
  478. package/src/plugins/builtin/volatility/series.ts +26 -0
  479. package/src/plugins/builtin/world-indices/footer.ts +1 -1
  480. package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
  481. package/src/plugins/catalog-browser.ts +13 -8
  482. package/src/plugins/catalog-manifest.ts +2 -1
  483. package/src/plugins/marketplace/model.ts +18 -5
  484. package/src/portfolio/column-values.ts +5 -5
  485. package/src/portfolio/futures-positions.ts +6 -3
  486. package/src/portfolio/position-quantity.ts +15 -9
  487. package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
  488. package/src/remote/resources.ts +2 -1
  489. package/src/renderers/browser/app-services.ts +1 -7
  490. package/src/renderers/browser/config-host.ts +2 -55
  491. package/src/renderers/browser/main.tsx +7 -57
  492. package/src/renderers/dom/data-table/row.tsx +26 -0
  493. package/src/renderers/dom/desktop/list-view.tsx +13 -10
  494. package/src/renderers/dom/desktop/query-bar.tsx +4 -2
  495. package/src/renderers/dom/desktop/select-field.tsx +4 -2
  496. package/src/renderers/dom/host/chart-surface.tsx +21 -0
  497. package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
  498. package/src/renderers/electrobun/bun/desktop/backend.ts +29 -7
  499. package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
  500. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
  501. package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
  502. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
  503. package/src/renderers/electrobun/bun/desktop/update.ts +173 -5
  504. package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
  505. package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
  506. package/src/renderers/electrobun/bun/index.ts +25 -1
  507. package/src/renderers/electrobun/shared/app-name.ts +30 -0
  508. package/src/renderers/electrobun/shared/protocol.ts +10 -0
  509. package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
  510. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  511. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
  512. package/src/renderers/electrobun/view/main.tsx +24 -1
  513. package/src/renderers/electrobun/view/news-source.ts +3 -1
  514. package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
  515. package/src/renderers/electrobun/view/view-ids.ts +85 -0
  516. package/src/renderers/opentui/start.tsx +5 -0
  517. package/src/renderers/opentui/toast-host.tsx +71 -43
  518. package/src/series/registry.ts +1 -0
  519. package/src/series/types.ts +6 -0
  520. package/src/series/validate.ts +1 -0
  521. package/src/sources/gloomberb-cloud/index.ts +1 -0
  522. package/src/sources/gloomberb-cloud/news.ts +47 -7
  523. package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
  524. package/src/sources/provider-router/batches.ts +10 -2
  525. package/src/sources/provider-router/financial-routes.ts +3 -3
  526. package/src/sources/provider-router/financials.ts +15 -3
  527. package/src/sources/provider-router/history.ts +28 -7
  528. package/src/sources/provider-router/index.ts +149 -10
  529. package/src/sources/provider-router/search.ts +13 -2
  530. package/src/state/app/context/index.tsx +3 -0
  531. package/src/state/ticker-cleanup.ts +50 -0
  532. package/src/sync/auth-transition.ts +19 -9
  533. package/src/sync/baseline.ts +10 -4
  534. package/src/sync/controller.ts +70 -19
  535. package/src/sync/core-contributors.ts +90 -31
  536. package/src/sync/react.ts +4 -1
  537. package/src/sync/types.ts +3 -0
  538. package/src/telemetry/stall-reports-dom.ts +38 -0
  539. package/src/telemetry/stall-reports-node.ts +75 -0
  540. package/src/telemetry/stall-reports.ts +214 -0
  541. package/src/telemetry/usage-counts.ts +0 -18
  542. package/src/test-support/preload.ts +14 -0
  543. package/src/theme/colors.ts +8 -0
  544. package/src/theme/themes.ts +10 -0
  545. package/src/tickers/company-name.ts +103 -3
  546. package/src/tickers/listing-venues.ts +38 -3
  547. package/src/tickers/search/bare-symbol.ts +36 -0
  548. package/src/tickers/search/index.ts +36 -7
  549. package/src/tickers/search/ranking.ts +10 -1
  550. package/src/tickers/search/types.ts +5 -0
  551. package/src/tickers/terminal-codes.ts +19 -0
  552. package/src/time-series/alignment.ts +1 -1
  553. package/src/time-series/base-series.ts +13 -5
  554. package/src/time-series/daily-valuation.ts +62 -0
  555. package/src/time-series/economic.ts +18 -4
  556. package/src/time-series/field-catalog.ts +2 -4
  557. package/src/time-series/filed-trailing-eps.ts +197 -0
  558. package/src/time-series/forward-valuation.ts +32 -0
  559. package/src/time-series/fundamentals.ts +198 -7
  560. package/src/time-series/hooks.ts +1 -0
  561. package/src/time-series/ice-credit.ts +3 -0
  562. package/src/time-series/price-comparison.ts +30 -2
  563. package/src/time-series/price-units.ts +72 -2
  564. package/src/time-series/resolve-context.ts +7 -1
  565. package/src/time-series/resolve.ts +116 -15
  566. package/src/time-series/series-presentation.ts +40 -6
  567. package/src/time-series/session-bar.ts +11 -0
  568. package/src/time-series/spec.ts +5 -3
  569. package/src/time-series/studies.ts +278 -74
  570. package/src/time-series/total-return.ts +160 -0
  571. package/src/time-series/transforms.ts +3 -3
  572. package/src/time-series/types.ts +27 -1
  573. package/src/time-series/valuation-releases.ts +39 -0
  574. package/src/types/data-provider.ts +9 -1
  575. package/src/types/desktop-window.ts +2 -0
  576. package/src/types/financials.ts +73 -2
  577. package/src/types/headless.ts +61 -5
  578. package/src/types/instrument.ts +3 -0
  579. package/src/types/news-source.ts +1 -0
  580. package/src/types/plugin.ts +10 -1
  581. package/src/ui/host.tsx +3 -0
  582. package/src/updater/command-names.ts +12 -7
  583. package/src/updater/failure.ts +4 -1
  584. package/src/utils/cli-output.ts +42 -1
  585. package/src/utils/crypto-pair.ts +44 -0
  586. package/src/utils/financial-statements.ts +6 -1
  587. package/src/utils/forward-dividend.ts +2 -0
  588. package/src/utils/fundamentals.ts +24 -3
  589. package/src/utils/fx-market-hours.ts +26 -3
  590. package/src/utils/main-thread-stall.ts +35 -2
  591. package/src/utils/market-capitalization.ts +24 -1
  592. package/src/utils/network-failure.ts +9 -6
  593. package/src/utils/option-expiry.ts +48 -1
  594. package/src/utils/options.ts +10 -0
  595. package/src/utils/plugin-proxy-hosts.json +1 -0
  596. package/src/utils/price-history.ts +12 -1
  597. package/src/utils/shell-word.ts +8 -0
  598. package/src/utils/trailing-dividend.ts +53 -4
  599. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
  600. package/src/renderers/browser/first-screen.ts +0 -193
@@ -2,40 +2,31 @@ import type { FundMember } from "../../../api-client/members";
2
2
  import type { Portfolio, Watchlist } from "../../../types/ticker";
3
3
  import { getSectorCollection } from "../sectors/sector-data";
4
4
 
5
- /**
6
- * The fund whose holdings name each company's GICS sector: the S&P 500's, as
7
- * MEMB reads it. A Select Sector SPDR holds the S&P 500's companies of one
8
- * sector, so its members are these holdings in that sector.
9
- */
10
- export const SECTOR_HOLDINGS_FUND = "IVV";
5
+ /** Focused industries, named by the fund whose published holdings define the group. */
6
+ const INDUSTRIES = [
7
+ { etf: "SOXX", name: "Semiconductors" },
8
+ { etf: "XPH", name: "Pharmaceuticals" },
9
+ { etf: "XBI", name: "Biotech" },
10
+ { etf: "ITA", name: "Aerospace & defense" },
11
+ { etf: "KRE", name: "Regional banks" },
12
+ { etf: "IGV", name: "Software" },
13
+ { etf: "XRT", name: "Retail" },
14
+ { etf: "XHB", name: "Homebuilders" },
15
+ { etf: "XOP", name: "Oil & gas exploration" },
16
+ ] as const;
11
17
 
12
- /** The GICS sector each of SECT's sector funds holds, as the S&P 500's holdings name it. */
13
- const SECTOR_OF_FUND: Readonly<Record<string, readonly string[]>> = {
14
- XLK: ["Information Technology"],
15
- XLV: ["Health Care"],
16
- XLF: ["Financials"],
17
- XLY: ["Consumer Discretionary"],
18
- // The holdings file says "Communication"; GICS's own name is the longer one.
19
- XLC: ["Communication", "Communication Services"],
20
- XLI: ["Industrials"],
21
- XLP: ["Consumer Staples"],
22
- XLE: ["Energy"],
23
- XLU: ["Utilities"],
24
- XLRE: ["Real Estate"],
25
- XLB: ["Materials"],
26
- };
27
-
28
- /** Which companies ERN lists: the market's, the user's, one portfolio or watchlist, or one sector fund's. */
18
+ /** Which companies ERN lists: the market, the user's lists, or a fund's holdings. */
29
19
  export type EarningsScope =
30
20
  | { kind: "all" }
31
21
  | { kind: "mine" }
32
22
  | { kind: "portfolio" | "watchlist"; id: string; name: string }
33
- | { kind: "sector"; etf: string; name: string; sectors: readonly string[] };
23
+ | { kind: "fund"; etf: string; name: string };
34
24
 
35
25
  export interface EarningsScopeOption {
36
26
  value: string;
37
27
  label: string;
38
28
  description?: string;
29
+ group?: string;
39
30
  scope: EarningsScope;
40
31
  }
41
32
 
@@ -47,30 +38,28 @@ export const MINE_SCOPE = "mine";
47
38
  const kindNote = (name: string, kind: "Portfolio" | "Watchlist") =>
48
39
  name.toLowerCase().includes(kind.toLowerCase()) ? undefined : kind;
49
40
 
50
- /**
51
- * The choices of ERN's Names filter, in menu order: the market, every held or
52
- * watched name, each portfolio and watchlist, then SECT's sector funds, each
53
- * named with its fund ("Technology (XLK)").
54
- */
41
+ /** Personal lists, broad sectors and focused industries stay separate in the Names menu. */
55
42
  export function earningsScopeOptions(collections: { portfolios: readonly Portfolio[]; watchlists: readonly Watchlist[] }): EarningsScopeOption[] {
56
43
  return [
57
44
  { value: ALL_SCOPE, label: "All", scope: { kind: "all" } },
58
45
  { value: MINE_SCOPE, label: "Mine", description: "Portfolios and watchlists", scope: { kind: "mine" } },
59
46
  ...collections.portfolios.map((portfolio): EarningsScopeOption => ({
60
- value: `portfolio:${portfolio.id}`, label: portfolio.name, description: kindNote(portfolio.name, "Portfolio"),
47
+ value: `portfolio:${portfolio.id}`, label: portfolio.name, description: kindNote(portfolio.name, "Portfolio"), group: "Your lists",
61
48
  scope: { kind: "portfolio", id: portfolio.id, name: portfolio.name },
62
49
  })),
63
50
  ...collections.watchlists.map((watchlist): EarningsScopeOption => ({
64
- value: `watchlist:${watchlist.id}`, label: watchlist.name, description: kindNote(watchlist.name, "Watchlist"),
51
+ value: `watchlist:${watchlist.id}`, label: watchlist.name, description: kindNote(watchlist.name, "Watchlist"), group: "Your lists",
65
52
  scope: { kind: "watchlist", id: watchlist.id, name: watchlist.name },
66
53
  })),
67
- ...getSectorCollection("sectors").items.flatMap((sector): EarningsScopeOption[] => {
68
- const sectors = SECTOR_OF_FUND[sector.etf];
69
- return sectors ? [{
70
- value: `sector:${sector.etf}`, label: `${sector.name} (${sector.etf})`,
71
- scope: { kind: "sector", etf: sector.etf, name: sector.name, sectors },
72
- }] : [];
73
- }),
54
+ ...getSectorCollection("sectors").items.map((sector): EarningsScopeOption => ({
55
+ // Keep the saved sector choice when switching to that fund's own holdings.
56
+ value: `sector:${sector.etf}`, label: `${sector.name} (${sector.etf})`, group: "Sectors",
57
+ scope: { kind: "fund", etf: sector.etf, name: sector.name },
58
+ })),
59
+ ...INDUSTRIES.map((industry): EarningsScopeOption => ({
60
+ value: `industry:${industry.etf}`, label: `${industry.name} (${industry.etf})`, group: "Industries",
61
+ scope: { kind: "fund", etf: industry.etf, name: industry.name },
62
+ })),
74
63
  ];
75
64
  }
76
65
 
@@ -79,11 +68,10 @@ export function readEarningsScope(value: string, options: readonly EarningsScope
79
68
  return options.find((option) => option.value === value) ?? options[0]!;
80
69
  }
81
70
 
82
- /** A sector fund's companies: the S&P 500's holdings in its sector, largest weight first. */
83
- export function sectorSymbols(members: readonly FundMember[], sectors: readonly string[]): string[] {
84
- const symbols = members
85
- .filter((member) => member.symbol && member.sector && sectors.includes(member.sector))
71
+ /** A fund's companies, largest weight first; cash and other unlisted holdings have no symbol. */
72
+ export function fundSymbols(members: readonly FundMember[]): string[] {
73
+ const symbols = [...members]
86
74
  .sort((left, right) => (right.weight ?? 0) - (left.weight ?? 0))
87
- .map((member) => member.symbol!.trim().toUpperCase());
75
+ .flatMap((member) => member.symbol?.trim() ? [member.symbol.trim().toUpperCase()] : []);
88
76
  return [...new Set(symbols)];
89
77
  }
@@ -29,7 +29,7 @@ import { usePluginPaneState } from "../../runtime";
29
29
  import { newYorkToday } from "../earnings/board-model";
30
30
  import { ProWall, SignInWall } from "../cloud/auth-actions";
31
31
  import { cachedUpcomingCalls, calendarAway, loadUpcomingCalls, statusOf, upcomingCutNotice, type UpcomingCallsResult } from "./data";
32
- import { formatPeriod } from "./format";
32
+ import { callPeriod } from "./format";
33
33
  import {
34
34
  calendarDays,
35
35
  calendarSections,
@@ -106,7 +106,7 @@ function renderCalendarCell(row: CalendarRow, column: CalendarColumn, now: numbe
106
106
  return clock ? { text: clock, color: tone(colors.textDim) } : { text: MISSING, color: colors.textMuted };
107
107
  }
108
108
  case "period":
109
- return { text: formatPeriod(call.fiscalYear, call.fiscalQuarter), color: tone(colors.textDim) };
109
+ return { text: callPeriod(call), color: tone(colors.textDim) };
110
110
  case "away":
111
111
  return { text: calendarAway(call, now), color: over ? colors.textMuted : colors.textBright };
112
112
  }
@@ -2,7 +2,7 @@ import type { CloudEarningsCallPayload } from "../../../api-client";
2
2
  import { formatShortDate } from "../../../utils/datetime-format";
3
3
 
4
4
  /** "FQ4 26" — fiscal period, compact enough for a table column. */
5
- export function formatPeriod(
5
+ function formatPeriod(
6
6
  fiscalYear: number | null,
7
7
  fiscalQuarter: number | null,
8
8
  ): string {
@@ -36,8 +36,37 @@ export function formatTimestamp(seconds: number): string {
36
36
  return `${minutes}:${String(remainder).padStart(2, "0")}`;
37
37
  }
38
38
 
39
+ type NamedCall = Pick<
40
+ CloudEarningsCallPayload,
41
+ "ticker" | "fiscalYear" | "fiscalQuarter" | "eventKind" | "eventLabel"
42
+ >;
43
+
44
+ /** An event that is not an earnings call (a deal call, an investor day), shown by its label and never as a quarter. */
45
+ export function eventLabelOf(call: Omit<NamedCall, "ticker">): string | null {
46
+ return call.eventKind === "other" && call.eventLabel ? call.eventLabel : null;
47
+ }
48
+
49
+ // Fits the period column; the full label is in the detail title.
50
+ const SHORT_EVENT_LABELS: Record<string, string> = {
51
+ "M&A call": "M&A",
52
+ conference: "Conf",
53
+ "investor day": "Inv day",
54
+ "business update": "Update",
55
+ "trial results": "Trial",
56
+ "shareholder call": "Holders",
57
+ };
58
+
59
+ /** The period column: "FQ4 26", or a short event label ("M&A", "Inv day"). */
60
+ export function callPeriod(call: Omit<NamedCall, "ticker">): string {
61
+ const label = eventLabelOf(call);
62
+ if (label) return SHORT_EVENT_LABELS[label] ?? label;
63
+ return formatPeriod(call.fiscalYear, call.fiscalQuarter);
64
+ }
65
+
39
66
  /** Title for the detail stack: names the call so the body need not repeat it. */
40
- export function callTitle(call: CloudEarningsCallPayload): string {
67
+ export function callTitle(call: NamedCall): string {
68
+ const label = eventLabelOf(call);
69
+ if (label) return `${call.ticker} ${label}`;
41
70
  const period = formatPeriod(call.fiscalYear, call.fiscalQuarter);
42
71
  return period === "—" ? call.ticker : `${call.ticker} ${period}`;
43
72
  }
@@ -23,7 +23,7 @@ import {
23
23
  type UpcomingCallsResult,
24
24
  type UpcomingDays,
25
25
  } from "./data";
26
- import { formatPeriod } from "./format";
26
+ import { callPeriod, eventLabelOf } from "./format";
27
27
  import type { MarketDay } from "../earnings/board-model";
28
28
  import {
29
29
  calendarDays,
@@ -53,6 +53,7 @@ const CALL_COLUMNS = [
53
53
  { key: "callAt", header: "Call date" },
54
54
  { key: "fiscalYear", header: "FY", align: "right" as const },
55
55
  { key: "fiscalQuarter", header: "FQ", align: "right" as const },
56
+ { key: "event", header: "Event" },
56
57
  { key: "status", header: "Status" },
57
58
  { key: "durationSeconds", header: "Seconds", align: "right" as const },
58
59
  { key: "wordCount", header: "Words", align: "right" as const },
@@ -124,6 +125,8 @@ function callRow(call: CloudEarningsCallPayload, now: number) {
124
125
  callAt: call.callAt,
125
126
  fiscalYear: call.fiscalYear,
126
127
  fiscalQuarter: call.fiscalQuarter,
128
+ // A deal call, a conference, an investor day: not a quarter's earnings call.
129
+ event: eventLabelOf(call),
127
130
  status: call.hasTranscript ? "transcribed" : callStatusLabel(call, now) || call.status,
128
131
  upcoming,
129
132
  in: upcoming ? callCountdown(call, now) : null,
@@ -219,6 +222,7 @@ function transcriptResult(
219
222
  company: transcript.companyName,
220
223
  fiscalYear: transcript.fiscalYear,
221
224
  fiscalQuarter: transcript.fiscalQuarter,
225
+ event: eventLabelOf(transcript),
222
226
  callAt: transcript.callAt,
223
227
  durationSeconds: transcript.durationSeconds,
224
228
  wordCount: transcript.wordCount,
@@ -259,7 +263,8 @@ function projectCalendar(
259
263
  timeKnown: callTimeKnown(call),
260
264
  local: callLocalClock(call),
261
265
  newYork: callNewYorkClock(call),
262
- period: formatPeriod(call.fiscalYear, call.fiscalQuarter),
266
+ period: callPeriod(call),
267
+ event: eventLabelOf(call),
263
268
  fiscalYear: call.fiscalYear,
264
269
  fiscalQuarter: call.fiscalQuarter,
265
270
  in: calendarAway(call, now),
@@ -3,6 +3,7 @@ import type {
3
3
  CloudEarningsTranscriptPayload,
4
4
  CloudTranscriptTurnPayload,
5
5
  } from "../../../api-client";
6
+ import { eventLabelOf } from "./format";
6
7
  import { splitParagraphs } from "./prose";
7
8
 
8
9
  export type TranscriptSection =
@@ -210,7 +211,11 @@ export function findCallForQuarter(
210
211
  ): CloudEarningsCallPayload | null {
211
212
  const sorted = sortCallsNewest(calls);
212
213
  const token = requestedQuarter.trim().toUpperCase().replace(/[\s_-]+/g, "");
213
- if (!token || token === "LATEST") return sorted[0] ?? null;
214
+ // The latest earnings call: a deal call or an investor day held after it is
215
+ // not the quarter's call, unless the company has nothing else.
216
+ if (!token || token === "LATEST") {
217
+ return sorted.find((call) => !eventLabelOf(call)) ?? sorted[0] ?? null;
218
+ }
214
219
 
215
220
  const quarterFirst = token.match(/^(?:F?Q)?([1-4])(?:\/?(\d{2}|\d{4}))?$/);
216
221
  if (quarterFirst) {
@@ -49,7 +49,7 @@ import {
49
49
  loadTranscript,
50
50
  statusOf,
51
51
  } from "./data";
52
- import { callTitle, formatCallDate, formatDuration, formatPeriod, formatSentiment } from "./format";
52
+ import { callPeriod, callTitle, eventLabelOf, formatCallDate, formatDuration, formatSentiment } from "./format";
53
53
  import { findCallForQuarter, findInLines, MIN_FIND_LENGTH, turnParagraphs } from "./model";
54
54
  import { READER_TABS, TranscriptView, type ReaderTab, type TranscriptPlayback } from "./transcript-view";
55
55
  import { PLAYBACK_RATES, SEEK_STEP_SECONDS, useCallPlayback } from "./use-call-playback";
@@ -101,7 +101,7 @@ function renderCell(call: CloudEarningsCallPayload, column: CallColumn, now: num
101
101
  case "date":
102
102
  return { text: formatCallDate(call.callAt), color: colors.textDim };
103
103
  case "period":
104
- return { text: formatPeriod(call.fiscalYear, call.fiscalQuarter) };
104
+ return { text: callPeriod(call) };
105
105
  case "length":
106
106
  return { text: formatDuration(call.durationSeconds), color: colors.textDim };
107
107
  case "sentiment": {
@@ -525,7 +525,8 @@ function CallsListView({
525
525
  [
526
526
  call.ticker,
527
527
  call.companyName ?? "",
528
- formatPeriod(call.fiscalYear, call.fiscalQuarter),
528
+ callPeriod(call),
529
+ eventLabelOf(call) ?? "",
529
530
  formatCallDate(call.callAt),
530
531
  ]
531
532
  .join(" ")
@@ -1020,7 +1021,7 @@ function CallsListView({
1020
1021
  <AudioPlayer
1021
1022
  src={playback.audio.url}
1022
1023
  sourceKey={selected.id}
1023
- label={`${callTitle(selected)} call recording`}
1024
+ label={`${callTitle(selected)}${eventLabelOf(selected) ? "" : " call"} recording`}
1024
1025
  durationSeconds={playback.audio.durationSeconds}
1025
1026
  rates={PLAYBACK_RATES}
1026
1027
  rate={playback.rate}
@@ -3,6 +3,7 @@ import type { DataTableColumn } from "../../../components";
3
3
  import { colors } from "../../../theme/colors";
4
4
  import { displayWidth } from "../../../utils/format";
5
5
  import { fetchEconCalendar } from "./calendar-source";
6
+ import { parseEconFigure } from "./figures";
6
7
  import { isAllDayEvent, type EconEvent, type EconImpact } from "./types";
7
8
 
8
9
  const CACHE_KIND = "calendar";
@@ -172,6 +173,17 @@ export function matchesImpact(event: EconEvent, filter: ImpactFilter): boolean {
172
173
  return filter === "all" || event.impact === filter;
173
174
  }
174
175
 
176
+ /**
177
+ * The releases of the region that the High filter, where the calendar opens,
178
+ * leaves out (most PMIs among them), for the footer and a report of the pane
179
+ * to count with the way to list them. None under All, and none under Medium
180
+ * or Low, which a reader picks to list one level.
181
+ */
182
+ export function lowerImpactHidden(events: readonly EconEvent[], impact: ImpactFilter, country: CountryFilter): number {
183
+ if (impact !== "high") return 0;
184
+ return events.filter((event) => event.impact !== "high" && matchesCountry(event, country)).length;
185
+ }
186
+
175
187
  const IMPACT_WORDS: Record<Exclude<ImpactFilter, "all">, string> = {
176
188
  high: "high-impact",
177
189
  medium: "medium-impact",
@@ -387,16 +399,9 @@ export function valueColumnWidth(events: readonly EconEvent[], key: "actual" | "
387
399
  return width;
388
400
  }
389
401
 
390
- function parseNumeric(value: string | null): number | null {
391
- if (!value) return null;
392
- const cleaned = value.replace(/[%,KMBTkmbts]/g, "").trim();
393
- const n = parseFloat(cleaned);
394
- return isNaN(n) ? null : n;
395
- }
396
-
397
402
  export function actualColor(actual: string | null, forecast: string | null): string {
398
- const a = parseNumeric(actual);
399
- const f = parseNumeric(forecast);
403
+ const a = parseEconFigure(actual)?.value ?? null;
404
+ const f = parseEconFigure(forecast)?.value ?? null;
400
405
  if (a === null || f === null) return colors.text;
401
406
  if (a > f) return colors.positive;
402
407
  if (a < f) return colors.negative;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The figures of an economic calendar row as numbers. The calendar serves
3
+ * Actual, Forecast and Prior as the text a table prints (`3%`, `30.3K`,
4
+ * `-4.1M bbl`, `77 Bcf`); an export reads them back so a script gets a number
5
+ * and what it is a number of.
6
+ */
7
+
8
+ /** A figure read back from its text. */
9
+ export interface EconFigure {
10
+ /** The figure in its unit, its scale multiplied out: `30.3K` is 30300 and `3%` is 3. */
11
+ value: number;
12
+ /** What the figure counts: `%`, `bbl`, `b/d`, `Bcf`; empty for a plain count or index level. */
13
+ unit: string;
14
+ /** The multiplier the text drew it in: 1, or 1000 for `K`, 1e6 for `M`, 1e9 for `B`, 1e12 for `T`. */
15
+ scale: number;
16
+ }
17
+
18
+ const SCALE_DIGITS: Readonly<Record<string, number>> = { K: 3, M: 6, B: 9, T: 12 };
19
+
20
+ // A sign, then the digits (grouped by commas, or with a decimal point or comma), a scale letter straight after them,
21
+ // then `%` or a unit word: `-4.1M bbl`, `3%`, `30k`, `1,250`, `1,5%`, `77 Bcf`, `50.9`. A range, a bound (`<1.25%`)
22
+ // or a figure with more words after it (`3% y/y`) is not one.
23
+ const FIGURE = /^([+-]?)(?:(\d{1,3}(?:,\d{3})+(?:\.\d+)?)|(\d+(?:[.,]\d+)?|\.\d+))(?:([KMBT])(?![A-Za-z]))?(?:(%)|\s*([A-Za-z][A-Za-z/.]*(?:\s+[A-Za-z/.]+)*))?$/i;
24
+
25
+ /**
26
+ * The number, unit and scale of a figure the calendar prints; null for a text
27
+ * that is not one figure (`<1.25%` is a bound, not a value) and for a missing one.
28
+ * The one reading of a figure: the table's colours and every export use it, so
29
+ * a figure the app can read is never a null in an export.
30
+ */
31
+ export function parseEconFigure(text: string | null | undefined): EconFigure | null {
32
+ const match = FIGURE.exec((text ?? "").trim().replace(/\u2212/g, "-"));
33
+ if (!match) return null;
34
+ const [, sign, grouped, plain, letter, percent, word] = match;
35
+ const digits = letter ? SCALE_DIGITS[letter.toUpperCase()]! : 0;
36
+ // A comma before exactly three digits groups thousands (1,250); before fewer it is a decimal comma (1,5).
37
+ const number = grouped ? grouped.replace(/,/g, "") : plain!.replace(",", ".");
38
+ // Parsed from the decimal text, so 0.987M is exactly 987000 and not 986999.9999999999.
39
+ const value = Number(`${sign === "-" ? "-" : ""}${number}e${digits}`);
40
+ return { value: Object.is(value, -0) ? 0 : value, unit: percent ? "%" : word ?? "", scale: 10 ** digits };
41
+ }
42
+
43
+ /** What a row's Actual, Forecast and Prior say in numbers, with the unit they share and the scale the first is drawn in. */
44
+ export interface EconRowFigures {
45
+ actual: number | null;
46
+ forecast: number | null;
47
+ prior: number | null;
48
+ /** The unit of the row's figures; null when it has no figure or they are plain counts. */
49
+ unit: string | null;
50
+ /**
51
+ * The scale the first of its figures is drawn in (actual, else forecast, else prior); null when it has none.
52
+ * Each figure is multiplied out by its own, so `950K` beside `1.2M` is 950000 and 1200000 under scale 1000.
53
+ */
54
+ scale: number | null;
55
+ }
56
+
57
+ /**
58
+ * A row's three figures as numbers. They share one unit; a figure drawn in
59
+ * another (none is today) is null rather than a number in the wrong unit.
60
+ */
61
+ export function econRowFigures(row: { actual?: string | null; forecast?: string | null; prior?: string | null }): EconRowFigures {
62
+ const figures = [row.actual, row.forecast, row.prior].map(parseEconFigure);
63
+ const first = figures.find((figure): figure is EconFigure => figure != null);
64
+ const numbers = figures.map((figure) => figure && first && figure.unit === first.unit ? figure.value : null);
65
+ return {
66
+ actual: numbers[0]!,
67
+ forecast: numbers[1]!,
68
+ prior: numbers[2]!,
69
+ unit: first?.unit ? first.unit : null,
70
+ scale: first?.scale ?? null,
71
+ };
72
+ }
@@ -46,6 +46,7 @@ import {
46
46
  subscribeCalendar,
47
47
  impactIndicator,
48
48
  loadCalendar,
49
+ lowerImpactHidden,
49
50
  eventCountry,
50
51
  matchesCountry,
51
52
  matchesImpact,
@@ -103,7 +104,10 @@ function EconCalendarPane({ focused, width, height }: PaneProps) {
103
104
  // The selected row and the open event are remembered by event id, so a
104
105
  // reload or a shared layout comes back to the same release.
105
106
  const [selectedKey, setSelectedKey] = usePluginPaneState<string | null>("selectedKey", null);
106
- const [impactFilter, setImpactFilter] = usePluginPaneState<ImpactFilter>("impactFilter", DEFAULT_IMPACT_FILTER);
107
+ // A level a caller named (`fn ECO --impact all`) is where a new pane opens; a level the reader picks is kept.
108
+ const [impactSetting] = usePaneSettingValue<string>("impact", "");
109
+ const openingImpact = FILTER_CYCLE.find((level) => level === impactSetting) ?? DEFAULT_IMPACT_FILTER;
110
+ const [impactFilter, setImpactFilter] = usePluginPaneState<ImpactFilter>("impactFilter", openingImpact);
107
111
  const [chosenCountry, setCountryFilter] = usePluginPaneState<CountryFilter>("countryFilter", "all");
108
112
  // Countries a caller named (`ECO MX,BR`, `fn ECO --country MX`) are shown once per request; a later choice is the reader's.
109
113
  const pane = usePaneInstance();
@@ -323,12 +327,22 @@ function EconCalendarPane({ focused, width, height }: PaneProps) {
323
327
  const showStale = stale && (!loading || calendar.updatedAt !== null);
324
328
  // An empty list says it in its empty state instead.
325
329
  const listedAfterStatus = listedAfter && !detailEvent && filtered.length > 0 ? listedAfter : null;
330
+ // What the High filter, where the calendar opens, leaves out, and the key that lists it (Shift+F steps back to All).
331
+ const hiddenCount = useMemo(() => lowerImpactHidden(events, impactFilter, countryFilter), [countryFilter, events, impactFilter]);
332
+ const hiddenStatus = hiddenCount > 0 && !detailEvent ? `${hiddenCount} lower-impact hidden` : null;
326
333
  const calendarStatus = useMemo<PaneFooterSegment[]>(() => [
334
+ ...(hiddenStatus ? [{
335
+ id: "hidden-impact",
336
+ capture: true,
337
+ title: `${hiddenStatus}: Shift+F or Impact All lists them`,
338
+ // First and whole: the countdown and the update time give way before the key does.
339
+ parts: [{ text: `${hiddenStatus} (Shift+F)`, tone: "muted" as const }],
340
+ }] : []),
327
341
  ...(nextText && !detailEvent ? [{ id: "next", parts: [{ text: nextText, tone: "muted" as const }] }] : []),
328
342
  ...(listedAfterStatus ? [{ id: "listed-after", parts: [{ text: listedAfterStatus, tone: "warning" as const }] }] : []),
329
343
  ...(showStale ? [{ id: "stale", parts: [{ text: "STALE", tone: "warning" as const }] }] : []),
330
344
  ...(staleness ? [{ id: "updated", parts: [{ text: staleness, tone: "muted" as const }] }] : []),
331
- ], [detailEvent, listedAfterStatus, nextText, showStale, staleness]);
345
+ ], [detailEvent, hiddenStatus, listedAfterStatus, nextText, showStale, staleness]);
332
346
  // A report of the pane (`gloom fn ECO`) says it too.
333
347
  const listedThrough = listedEnd ? dateKey(listedEnd) : null;
334
348
  useRemoteUiNode(listedAfter && listedThrough ? {
@@ -336,6 +350,15 @@ function EconCalendarPane({ focused, width, height }: PaneProps) {
336
350
  label: "Listed through",
337
351
  getMetadata: () => ({ text: listedAfter, key: "listedThrough", value: listedThrough }),
338
352
  } : null);
353
+ useRemoteUiNode(hiddenCount > 0 ? {
354
+ role: "report-notice",
355
+ label: "Lower-impact hidden",
356
+ getMetadata: () => ({
357
+ text: `${hiddenCount} lower-impact ${hiddenCount === 1 ? "release" : "releases"} hidden: add --impact all to list them.`,
358
+ key: "lowerImpactHidden",
359
+ value: hiddenCount,
360
+ }),
361
+ } : null);
339
362
  usePaneStatusFooter({
340
363
  registrationId: "econ-calendar",
341
364
  loading,
@@ -527,6 +550,13 @@ export const economicCalendarModule: PluginModule = {
527
550
  if ("error" in parsed) throw new Error(`${parsed.error} ${COUNTRY_FILTER_HINT}`);
528
551
  return parsed.filter;
529
552
  },
553
+ }, {
554
+ key: "impact",
555
+ type: "enum",
556
+ values: [{ value: "high" }, { value: "medium", aliases: ["med"] }, { value: "low" }, { value: "all" }],
557
+ description: "Impact level to list: high (where the calendar opens, leaving out most PMIs), medium, low or all",
558
+ example: "--impact all",
559
+ exampleWithoutArgument: true,
530
560
  }],
531
561
  settings: {
532
562
  title: "Economic Calendar Settings",
@@ -546,7 +576,7 @@ export const economicCalendarModule: PluginModule = {
546
576
  description: "Upcoming economic events, releases, and indicators.",
547
577
  // "econ" stays a keyword so the old ECON prefix still finds this pane.
548
578
  keywords: ["econ", "economic", "calendar", "events", "macro", "releases", "fed", "cpi", "gdp", "rate decision", "ipca",
549
- "brazil inflation"],
579
+ "brazil inflation", "pmi", "ism", "purchasing managers", "flash pmi"],
550
580
  // ECO MX,BR opens the calendar on those countries.
551
581
  shortcut: {
552
582
  prefix: "ECO",
@@ -27,6 +27,10 @@ export interface EconEvent {
27
27
  referencePeriod?: string | null;
28
28
  /** Who publishes it (Freddie Mac for the 30-year mortgage rate), and its page when one is named. */
29
29
  source?: { name: string; url?: string };
30
+ /** The indicator this release is of, the same from one release to the next; `id` is this row's alone. */
31
+ indicatorId?: string | null;
32
+ /** Which feed the forecast was read from (`week-feed`, `release-calendar`) and when that feed was read. */
33
+ consensus?: { source: string; readAt: string } | null;
30
34
  }
31
35
 
32
36
  /** Whether a row's time is blank because its publisher states none (a bank whose calendar gives the day only). */
@@ -60,6 +60,12 @@ export interface StatDef {
60
60
  note: string;
61
61
  /** Other words the catalog and the pane's filter find it by: `PMMS` for the mortgage rate. */
62
62
  keywords?: readonly string[];
63
+ /**
64
+ * The names a reader gives the indicator, read as an argument ahead of any
65
+ * FRED series id: `PCE` is the price index release, not the series FRED files
66
+ * under that id (personal spending), and `gdp` is real GDP, not its nowcast.
67
+ */
68
+ aliases?: readonly string[];
63
69
  /** Concise measurement identity that must remain beside the values. */
64
70
  measurementBasis?: string;
65
71
  /**