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
@@ -86,6 +86,7 @@ const STREAM_QUOTE_MAX_SILENCE_MS = 75_000;
86
86
  const uncertainPlacement = "Outcome unknown. Check open orders before placing it again.";
87
87
  /** A change or cancel whose answer was lost: the views ask the broker until it says. */
88
88
  const uncertainChange = "Outcome unknown. Checking with the broker.";
89
+ const orderReadFailed = "Order status could not be read. Showing the last known order.";
89
90
  /** The broker's own words come first: they say more than "outcome unknown". */
90
91
  const uncertainAfter = (error: unknown) => error instanceof Error && error.message && !error.message.includes(uncertainPlacement) ? `${error.message.trim().replace(/\.?$/, ".")} ${uncertainPlacement}` : uncertainPlacement;
91
92
  /** The broker answered no, or nothing was sent (see BrokerAdapter.placeOrder): its one-line reason, else undefined. */
@@ -639,7 +640,7 @@ export class BrokerTradingController {
639
640
  && value.contract.symbol === order.contract.symbol && (value.orderId === order.orderId || sameOrder(value, order)));
640
641
  } catch (error) {
641
642
  logFailure("broker-trading.controller", "Look up broker order failed")(error);
642
- return undefined;
643
+ throw new Error(orderReadFailed);
643
644
  }
644
645
  }
645
646
 
@@ -651,7 +652,10 @@ export class BrokerTradingController {
651
652
  */
652
653
  private async settleRefusal(order: BrokerOrder, reason: string, action: "modify" | "cancel"): Promise<void> {
653
654
  const brokerName = this.context(false).context.adapter.name;
654
- const current = await this.lookup(order);
655
+ let current: BrokerOrder | undefined;
656
+ let readFailed = false;
657
+ try { current = await this.lookup(order); }
658
+ catch { readFailed = true; reason = `${reason}. ${orderReadFailed}`; }
655
659
  if (this.disposed) return;
656
660
  const now = current ?? order;
657
661
  const label = brokerOrderStatus(now.status);
@@ -662,7 +666,7 @@ export class BrokerTradingController {
662
666
  this.publish({ phase: "editing", review: undefined, receipt: undefined, error: reason });
663
667
  return;
664
668
  }
665
- this.publish({ phase: "result", cancelOrder: undefined, review: undefined, result: copy(now), resultQuantities: current ? "confirmed" : "last-known", error: undefined });
669
+ this.publish({ phase: "result", cancelOrder: undefined, review: undefined, result: copy(now), resultQuantities: current ? "confirmed" : "last-known", error: readFailed ? reason : undefined });
666
670
  const title = ended ? label === "Rejected" ? reason : `Already ${label.toLowerCase()}` : changed ? `Order changed in ${brokerName}, refreshed` : reason;
667
671
  this.options.onOutcome?.({ title, type: ended || changed ? "info" : "error", order: copy(now) });
668
672
  }
@@ -677,16 +681,22 @@ export class BrokerTradingController {
677
681
  async refreshResult(): Promise<void> {
678
682
  const result = this.snapshot.result;
679
683
  if (!result) return;
680
- const { context } = this.context(false);
681
- if (!context.adapter.listOpenOrders && !context.adapter.getOrderStatus) throw new Error("Refresh this order in your broker.");
682
684
  const fingerprint = this.key();
683
- const orders = context.adapter.getOrderStatus && result.orderId !== 0
684
- ? [await context.adapter.getOrderStatus(context.instance, result.orderId)].filter((order): order is BrokerOrder => order !== null)
685
- : await context.adapter.listOpenOrders?.(context.instance) ?? [];
686
- if (this.disposed || fingerprint !== this.key() || this.snapshot.result !== result) return;
687
- const current = orders.find((order) => order.accountId === result.accountId && order.contract.symbol === result.contract.symbol && sameOrder(order, result));
688
- if (current) this.publish({ result: copy(current), resultQuantities: "confirmed", error: current.status === "UNKNOWN" ? uncertainChange : undefined });
689
- // Absence from open orders does not prove a fill, rejection or cancellation.
685
+ const stillCurrent = () => !this.disposed && fingerprint === this.key() && this.snapshot.result === result;
686
+ try {
687
+ const { context } = this.context(false);
688
+ if (!context.adapter.listOpenOrders && !context.adapter.getOrderStatus) throw new Error("Refresh this order in your broker.");
689
+ const orders = context.adapter.getOrderStatus && result.orderId !== 0
690
+ ? [await context.adapter.getOrderStatus(context.instance, result.orderId)].filter((order): order is BrokerOrder => order !== null)
691
+ : await context.adapter.listOpenOrders?.(context.instance) ?? [];
692
+ if (!stillCurrent()) return;
693
+ const current = orders.find((order) => order.accountId === result.accountId && order.contract.symbol === result.contract.symbol && sameOrder(order, result));
694
+ if (current) this.publish({ result: copy(current), resultQuantities: "confirmed", error: current.status === "UNKNOWN" ? uncertainChange : undefined });
695
+ // Absence from open orders does not prove a fill, rejection or cancellation, or clear a read failure.
696
+ } catch {
697
+ if (stillCurrent()) this.publish({ error: orderReadFailed, resultQuantities: this.snapshot.resultQuantities === "unconfirmed" ? "unconfirmed" : "last-known" });
698
+ throw new Error(orderReadFailed);
699
+ }
690
700
  }
691
701
 
692
702
  /**
@@ -32,7 +32,19 @@ export const brokerTradingModule: PluginModule = {
32
32
  }],
33
33
  setup(ctx) {
34
34
  brokerOrderFeed.setNotifier((notification) => { ctx.notify(notification); });
35
- brokerOrderFeed.setPositionSync((instanceId) => ctx.syncBrokerInstance(instanceId));
35
+ brokerOrderFeed.setPositionSync(async (instanceId) => {
36
+ try {
37
+ await ctx.syncBrokerInstance(instanceId);
38
+ } catch (error) {
39
+ ctx.notify({
40
+ title: "Position sync failed",
41
+ body: "The fill was received, but positions could not be synced. Use Sync in Brokers to retry.",
42
+ type: "error",
43
+ action: { label: "Brokers", onClick: () => ctx.showPane("brokers") },
44
+ });
45
+ throw error;
46
+ }
47
+ });
36
48
  let held = new Map<string, { key: string; release(): void }>();
37
49
  // A broker registered by a later plugin, or a profile added or edited, is held from then on.
38
50
  const holdProfiles = () => {
@@ -225,20 +225,24 @@ class ProfileOrderFeed {
225
225
  }
226
226
  // A working order missing from the list ended somehow; only the broker can say how.
227
227
  const missing = [...this.orders].filter(([key, order]) => !listed.has(key) && !brokerOrderDone(order.status));
228
+ let failed = false;
228
229
  for (const [key, order] of missing) {
229
230
  // A broker with no status read says nothing beyond its open list.
230
231
  if (!this.broker.getOrderStatus) { this.orders.delete(key); continue; }
231
- const status = await this.broker.getOrderStatus(this.instance, order.orderId).catch(logFailure("broker-trading.order-feed", "Read missing broker order status failed"));
232
+ const status = await this.broker.getOrderStatus(this.instance, order.orderId).catch((error) => {
233
+ logFailure("broker-trading.order-feed", "Read missing broker order status failed")(error);
234
+ failed = true;
235
+ });
232
236
  if (generation !== this.generation) return;
233
237
  if (status) this.apply(status, baseline ? "baseline" : "poll", false);
234
238
  // Null is the broker unable to confirm it, not an end: keep it, unconfirmed, at its last report's time,
235
239
  // so the next read that lists it or a status that answers replaces it.
236
240
  else if (status === null && brokerOrderStatus(order.status) !== "UNKNOWN") this.apply({ ...order, status: "UNKNOWN" }, baseline ? "baseline" : "poll", false);
237
241
  }
238
- this.failures = 0;
242
+ this.failures = failed ? this.failures + 1 : 0;
239
243
  this.baselined = true;
240
244
  this.prune();
241
- this.publish({ failed: false, loaded: true });
245
+ this.publish({ failed, loaded: true });
242
246
  } catch {
243
247
  if (generation === this.generation) { this.failures++; this.publish({ failed: true, loaded: true }); }
244
248
  } finally {
@@ -275,7 +279,8 @@ class ProfileOrderFeed {
275
279
 
276
280
  private publish(changes: Partial<BrokerOrderFeedState> = {}): void {
277
281
  const orders = [...this.orders.values()].sort((a, b) => b.updatedAt - a.updatedAt);
278
- this.state = Object.freeze({ ...this.state, ...changes, orders, live: this.live, updatedAt: Date.now(), fills: this.feed.fillCount(this.instance.id) });
282
+ const failed = changes.failed ?? this.state.failed;
283
+ this.state = Object.freeze({ ...this.state, ...changes, orders, live: this.live, updatedAt: failed ? this.state.updatedAt : Date.now(), fills: this.feed.fillCount(this.instance.id) });
279
284
  this.feed.changed();
280
285
  }
281
286
  }
@@ -480,7 +480,7 @@ function ProfileTicket({ broker, instance, contract, width, height, focused, ord
480
480
  accountType: accounts.find((account) => account.accountId === accountId)?.accountType,
481
481
  quote: state.quote?.quote, quoteStale: state.quote?.stale, legQuotes: state.quote?.legs, quoteData: connection?.quoteData,
482
482
  phase: page === "enable" ? "enable" : state.phase, draft: receipt?.request ?? draft, preview: state.review?.preview ?? receipt?.preview, warnings: state.review?.warnings ?? [], result: state.result, resultQuantities: state.resultQuantities,
483
- error: connection?.state === "error" && connection.message ? connection.message : error ?? state.error, reconnecting,
483
+ error: connection?.state === "error" && connection.message ? connection.message : error ?? state.error ?? (orderFeed.failed ? "Order status could not be read. Showing the last known orders." : undefined), reconnecting,
484
484
  position: position?.quantity, avgCost: position?.avgCost, positionPnl: position?.pnl, tradingEnabled: caps?.enabled === true,
485
485
  typedConfirmation: typed, connected, capabilities: caps, modifying: state.modifying, original: state.modifying ? controller.modifyingOrder() : undefined, defaultPriceLabel, confirmOrders: state.confirmOrders,
486
486
  initialFocus: focusReview ? "review" : state.modifying ? draft?.orderType === "STP" ? "stopPrice" : draft?.orderType === "TRAIL" ? "trailing" : "limitPrice" : focusRevision ? "review" : undefined,
@@ -12,11 +12,19 @@ import {
12
12
  activityLabel,
13
13
  criticalityColor,
14
14
  metricColor,
15
+ moneyAmount,
16
+ moneyText,
15
17
  text,
16
18
  tickerSymbol,
17
19
  } from "./format";
18
20
  import { favoriteKey } from "./table-model";
19
21
 
22
+ /** A dollar figure in the compact form, with its whole number for an export. */
23
+ function moneyCell(value: string | null | undefined, color: string): DataTableCell {
24
+ const amount = moneyAmount(value);
25
+ return { text: moneyText(value), ...(amount == null ? {} : { value: amount }), color };
26
+ }
27
+
20
28
  interface BuildoutCellContext {
21
29
  favoriteBusyKey: string | null;
22
30
  /** The row's last star did not take. */
@@ -40,7 +48,7 @@ export function renderBuildoutCell(
40
48
  case "companyCount":
41
49
  return { text: list.companyCount == null ? "-" : String(list.companyCount), color: colors.textDim };
42
50
  case "totalMarketCap":
43
- return { text: text(list.totalMarketCap), color: colors.textDim };
51
+ return moneyCell(list.totalMarketCap, colors.textDim);
44
52
  case "avgSectorGrowth":
45
53
  return { text: text(list.avgSectorGrowth), color: metricColor(list.avgSectorGrowth) };
46
54
  case "avgReturn1y":
@@ -87,16 +95,16 @@ export function renderBuildoutCell(
87
95
  case "criticality":
88
96
  return { text: text(company.aiCriticality), color: criticalityColor(company.aiCriticality), attributes: TextAttributes.BOLD };
89
97
  case "marketCap":
90
- return { text: text(company.marketCap), color: colors.textDim };
98
+ return moneyCell(company.marketCap, colors.textDim);
91
99
  case "revenue":
92
- return { text: text(company.revenue), color: colors.textDim };
100
+ return moneyCell(company.revenue, colors.textDim);
93
101
  case "revenueGrowth":
94
102
  return {
95
103
  text: text(company.revenueGrowthYoy ?? company.lastQuarterGrowth),
96
104
  color: metricColor(company.revenueGrowthYoy ?? company.lastQuarterGrowth),
97
105
  };
98
106
  case "netIncome":
99
- return { text: text(company.netIncome), color: metricColor(company.netIncome) };
107
+ return moneyCell(company.netIncome, metricColor(company.netIncome));
100
108
  case "margin":
101
109
  return { text: text(company.profitMargins), color: metricColor(company.profitMargins) };
102
110
  case "forwardPE":
@@ -44,6 +44,44 @@ export function metricNumber(value: unknown): number | null {
44
44
  return (negative ? -parsed : parsed) * multiplier;
45
45
  }
46
46
 
47
+ /** A dollar figure as the service prints it ("$5094.1B", "$-4.9B"); anything else is not money to reformat. */
48
+ const DOLLAR_STRING = /^-?\$-?[\d,]*\.?\d+\s*[KMBT]?$/i;
49
+
50
+ /** The dollars in a string the service prints as money, or null for anything else. */
51
+ export function moneyAmount(value: unknown): number | null {
52
+ return typeof value === "string" && DOLLAR_STRING.test(value.trim()) ? metricNumber(value) : null;
53
+ }
54
+
55
+ const MONEY_UNITS = [
56
+ { divisor: 1e12, suffix: "T" },
57
+ { divisor: 1e9, suffix: "B" },
58
+ { divisor: 1e6, suffix: "M" },
59
+ { divisor: 1e3, suffix: "K" },
60
+ ] as const;
61
+
62
+ /**
63
+ * Dollars in the one compact form every TheBuildout table uses: "$5.1T",
64
+ * "$356.4B", "-$4.9B". The unit is picked after rounding, so $999.96B is
65
+ * "$1.0T" and not "$1000.0B".
66
+ */
67
+ export function formatCompactMoney(amount: number): string {
68
+ const abs = Math.abs(amount);
69
+ let index = MONEY_UNITS.findIndex((unit) => abs >= unit.divisor);
70
+ let digits = index < 0 ? abs.toFixed(0) : (abs / MONEY_UNITS[index]!.divisor).toFixed(1);
71
+ if (index > 0 && Number(digits) >= 1000) {
72
+ index -= 1;
73
+ digits = (abs / MONEY_UNITS[index]!.divisor).toFixed(1);
74
+ }
75
+ const sign = amount < 0 && /[1-9]/.test(digits) ? "-" : "";
76
+ return `${sign}$${digits}${index < 0 ? "" : MONEY_UNITS[index]!.suffix}`;
77
+ }
78
+
79
+ /** A table cell's text for a dollar figure: compact when it is money, the service's own text otherwise, "-" when absent. */
80
+ export function moneyText(value: string | null | undefined): string {
81
+ const amount = moneyAmount(value);
82
+ return amount == null ? text(value) : formatCompactMoney(amount);
83
+ }
84
+
47
85
  export function dateShort(value: string | null | undefined) {
48
86
  const date = parseDisplayDate(value);
49
87
  if (!date) return "-";
@@ -1,4 +1,4 @@
1
- import { metricNumber, textOrNull, tickerSymbol, uniqueStrings } from "../format";
1
+ import { metricNumber, moneyAmount, textOrNull, tickerSymbol, uniqueStrings } from "../format";
2
2
  import type {
3
3
  BuildoutCompany,
4
4
  BuildoutList,
@@ -124,7 +124,42 @@ export function normalizeList(raw: RawObject): BuildoutList {
124
124
  };
125
125
  }
126
126
 
127
+ /**
128
+ * The statement figures a depositary receipt can carry in the issuer's
129
+ * reporting currency under a "$" and the receipt's USD currency: the service
130
+ * converts a foreign listing's figures and keeps the local ones as "...Original",
131
+ * but for an ADR it prints the local amounts as they are and names no currency
132
+ * (SK hynix's receipt shows the won revenue of its Korean listing as dollars).
133
+ */
134
+ const STATEMENT_FIELDS = ["revenue", "netIncome", "freeCashFlow", "operatingCashFlow", "totalCash", "totalDebt", "dilutedEps"] as const;
135
+
136
+ /** A yearly figure this many times the company's whole market value is not dollars. */
137
+ const IMPLAUSIBLE_MULTIPLE_OF_MARKET_CAP = 10;
138
+
139
+ /**
140
+ * A USD row with nothing converted whose revenue or net income dwarfs its own
141
+ * market cap has statements in another currency, and the row does not say
142
+ * which: the figures are left out rather than shown as wrong dollars. The
143
+ * ordinary range of revenue to market cap is a few times; the rows this
144
+ * catches sit at 15 to 4,000.
145
+ */
146
+ function withoutUnconvertedStatements(company: BuildoutCompany): BuildoutCompany {
147
+ const converted = [company.revenueOriginal, company.netIncomeOriginal].some((value) => textOrNull(value) != null);
148
+ const usd = (company.currency?.trim().toUpperCase() || "USD") === "USD";
149
+ const cap = moneyAmount(company.marketCap);
150
+ if (converted || !usd || cap == null || cap <= 0) return company;
151
+ const revenue = moneyAmount(company.revenue);
152
+ const income = moneyAmount(company.netIncome);
153
+ const limit = cap * IMPLAUSIBLE_MULTIPLE_OF_MARKET_CAP;
154
+ if ((revenue == null || Math.abs(revenue) <= limit) && (income == null || Math.abs(income) <= limit)) return company;
155
+ return { ...company, ...Object.fromEntries(STATEMENT_FIELDS.map((field) => [field, null])) };
156
+ }
157
+
127
158
  export function normalizeCompany(raw: RawObject): BuildoutCompany {
159
+ return withoutUnconvertedStatements(readCompany(raw));
160
+ }
161
+
162
+ function readCompany(raw: RawObject): BuildoutCompany {
128
163
  const ticker = tickerSymbol(stringField(raw, "ticker"));
129
164
  const name = stringField(raw, "name") ?? ticker ?? "Company";
130
165
  const supplyChain = objectField(raw, "supplyChain", "supply_chain");
@@ -160,7 +160,10 @@ export function BuildoutPane({ focused, width, height }: PaneProps) {
160
160
  const favoriteNotes = useRowNotes<BuildoutRow, string>(rows, { key: favoriteNoteKey });
161
161
  const { setNote: setFavoriteNote, noteFor: favoriteNoteFor } = favoriteNotes;
162
162
  clearFavoriteNotesRef.current = favoriteNotes.clearNotes;
163
- const columns = useMemo(() => columnsForTab(activeTab, selectedList, canFavorite), [activeTab, canFavorite, selectedList]);
163
+ const columns = useMemo(
164
+ () => columnsForTab(activeTab, selectedList, canFavorite, width),
165
+ [activeTab, canFavorite, selectedList, width],
166
+ );
164
167
  const selectedRow = rows[selectedIndex] ?? rows[0] ?? null;
165
168
  // The table's cells carry their own badges; this catalog only serves the open
166
169
  // detail: its row's tickers, plus the loaded rows' tickers its text mentions.
@@ -8,6 +8,7 @@ import type {
8
8
  BuildoutTabId,
9
9
  SortComparable,
10
10
  } from "./model/types";
11
+ import { dropColumnsToFit } from "../../../components/ui/table-layout";
11
12
  import type { SortDirection } from "../../../utils/sort-values";
12
13
  import { metricNumber, sourceDetailEntries, textOrNull, tickerSymbol } from "./format";
13
14
 
@@ -171,9 +172,29 @@ export function activeRows(
171
172
  return state.intel.items.map((item) => ({ kind: "intel", item }));
172
173
  }
173
174
 
174
- export function columnsForTab(activeTab: BuildoutTabId, selectedList: BuildoutList | null, canFavorite: boolean) {
175
+ /**
176
+ * What the Companies tab gives up when the pane is too narrow for its figures,
177
+ * least needed first: the descriptions, then the columns that only add to a
178
+ * figure already shown, instead of the right edge cutting Market Cap or a
179
+ * median. The star and the names stay at every width.
180
+ */
181
+ const LIST_DROP_ORDER: readonly BuildoutColumnId[] = ["listDescription", "avgMargin", "avgReturn1y", "avgSectorGrowth"];
182
+ const COMPANY_DROP_ORDER: readonly BuildoutColumnId[] = [
183
+ "description", "employees", "dividendYield", "forwardPE", "netIncome", "margin", "sectorTech", "criticality",
184
+ ];
185
+
186
+ /** The columns of a tab for a pane `width` cells wide; the table's scrollbar keeps its cell. */
187
+ export function columnsForTab(
188
+ activeTab: BuildoutTabId,
189
+ selectedList: BuildoutList | null,
190
+ canFavorite: boolean,
191
+ width: number,
192
+ ): BuildoutColumn[] {
175
193
  if (activeTab === "companies") {
176
- return selectedList && canFavorite ? [favoriteColumn, ...companyColumns] : selectedList ? companyColumns : listColumns;
194
+ const columns = selectedList
195
+ ? canFavorite ? [favoriteColumn, ...companyColumns] : companyColumns
196
+ : listColumns;
197
+ return dropColumnsToFit(columns, width - 1, selectedList ? COMPANY_DROP_ORDER : LIST_DROP_ORDER);
177
198
  }
178
199
  if (activeTab === "sites") return canFavorite ? [favoriteColumn, ...siteColumns] : siteColumns;
179
200
  return intelColumns;
@@ -1,11 +1,14 @@
1
1
  // Identity of the built-in composite plugins, shared by the native catalog and
2
2
  // the browser catalog (catalog-browser.ts). Keep this file import-free so the
3
- // browser catalog can read it without pulling in native-only modules.
3
+ // browser catalog can read it without pulling in native-only modules; the
4
+ // one import, ATTN's listing flag, has none of its own.
4
5
  //
5
- // Screeners & Movers, Ownership & Insiders and Earnings ship fewer panes on
6
+ // Screeners & Movers and Ownership & Insiders ship fewer panes on
6
7
  // the web, so each catalog gives them their own description rather than
7
8
  // advertising panes they lack.
8
9
 
10
+ import { ATTENTION_LISTED } from "./attention/listing";
11
+
9
12
  export const applicationPluginMeta = {
10
13
  id: "application",
11
14
  name: "Application",
@@ -116,7 +119,8 @@ export const altDataPluginMeta = {
116
119
  stateId: "ticker-research",
117
120
  name: "Supply Chain & Alt Data",
118
121
  version: "1.0.0",
119
- description: "Supply chains and exposure, government awards, hiring, apps and job postings, social mentions, research attention, GPU prices, and power queues.",
122
+ // Research attention joins once ATTN is listed again (attention/listing.ts).
123
+ description: `Supply chains and exposure, government awards, hiring, apps and job postings, social mentions, ${ATTENTION_LISTED ? "research attention, " : ""}GPU prices, and power queues.`,
120
124
  toggleable: true,
121
125
  };
122
126
 
@@ -122,11 +122,12 @@ export function catalystStatusTone(status: string): StateTone {
122
122
  return STATUS_TONES.find(([pattern]) => pattern.test(text))?.[1] ?? "text";
123
123
  }
124
124
 
125
- /** Event types: the adverse ones amber, the binary decisions in the accent, routine rulemaking quiet. */
125
+ /** Event types: the adverse ones amber, the binary decisions in the accent, routine rulemaking quiet, a company's own dates plain. */
126
126
  const TYPE_TONES: Record<CatalystType, StateTone> = {
127
127
  litigation: "warning", antitrust: "warning", recall: "warning", sanctions: "warning", export_control: "warning", tariff: "warning",
128
128
  pdufa: "accent", advisory: "accent", approval: "accent", clinical: "text",
129
129
  regulatory: "muted", rulemaking: "muted",
130
+ results: "text", shareholder_meeting: "text", merger_vote: "text", deal_closing: "text", investor_day: "text",
130
131
  };
131
132
  export const catalystTypeTone = (type: CatalystType): StateTone => TYPE_TONES[type] ?? "text";
132
133
  function changeValue(value: unknown): string {
@@ -11,6 +11,7 @@ import {
11
11
  } from "../../../components";
12
12
  import { DetailReader } from "../../../components/reader/detail-reader";
13
13
  import { loadingErrorFooterInfo, usePaneRefreshKey } from "../../../components/data-table/table-pane";
14
+ import { createTtlCache } from "../../../data/ttl-cache";
14
15
  import { fetchChangelogReleases, type ChangelogRelease } from "../../../updater/github-releases";
15
16
  import { colors } from "../../../theme/colors";
16
17
  import type { PaneProps } from "../../../types/plugin";
@@ -32,7 +33,8 @@ const CHANGELOG_CACHE_TTL_MS = 10 * 60 * 1000;
32
33
 
33
34
  // Process-lifetime cache. Move it into the updater module if other
34
35
  // surfaces start reading releases too.
35
- let cachedReleases: { releases: ChangelogRelease[]; fetchedAt: number } | null = null;
36
+ const releaseCache = createTtlCache<ChangelogRelease[]>({ ttlMs: CHANGELOG_CACHE_TTL_MS });
37
+ const RELEASES = "releases";
36
38
 
37
39
  type ChangelogColumn = DataTableColumn & { id: ChangelogColumnId };
38
40
  type LoadStatus = "loading" | "loaded" | "error";
@@ -83,10 +85,10 @@ function ChangelogDetail({
83
85
  function ChangelogPane({ focused, width, height }: PaneProps) {
84
86
  const paneInstance = usePaneInstance();
85
87
  const requestedVersion = paneInstance?.params?.version ?? null;
86
- const [releases, setReleases] = useState<ChangelogRelease[]>(() => cachedReleases?.releases ?? []);
88
+ const [releases, setReleases] = useState<ChangelogRelease[]>(() => releaseCache.peek(RELEASES, { stale: true }) ?? []);
87
89
  // The mount effect starts the request immediately, so the first paint is a
88
90
  // spinner and never "No changelog entries found".
89
- const [status, setStatus] = useState<LoadStatus>(() => (cachedReleases ? "loaded" : "loading"));
91
+ const [status, setStatus] = useState<LoadStatus>(() => (releaseCache.peek(RELEASES, { stale: true }) ? "loaded" : "loading"));
90
92
  const [error, setError] = useState<string | null>(null);
91
93
  // The selected row and the open release are pane state, so a reload or a
92
94
  // shared layout comes back to the same release.
@@ -98,8 +100,9 @@ function ChangelogPane({ focused, width, height }: PaneProps) {
98
100
  const requestedVersionOpenedRef = useRef(false);
99
101
 
100
102
  const loadReleases = useCallback(async (force = false) => {
101
- if (!force && cachedReleases && Date.now() - cachedReleases.fetchedAt < CHANGELOG_CACHE_TTL_MS) {
102
- setReleases(cachedReleases.releases);
103
+ const fresh = force ? undefined : releaseCache.peek(RELEASES);
104
+ if (fresh) {
105
+ setReleases(fresh);
103
106
  setError(null);
104
107
  setStatus("loaded");
105
108
  return;
@@ -118,7 +121,7 @@ function ChangelogPane({ focused, width, height }: PaneProps) {
118
121
 
119
122
  try {
120
123
  const nextReleases = await fetchChangelogReleases(CHANGELOG_LIMIT, controller.signal);
121
- cachedReleases = { releases: nextReleases, fetchedAt: Date.now() };
124
+ releaseCache.set(RELEASES, nextReleases);
122
125
  setReleases(nextReleases);
123
126
  setStatus("loaded");
124
127
  } catch (loadError) {
@@ -6,6 +6,7 @@ import {
6
6
  import type { SeriesCatalogEntry, SeriesFrequency, SeriesInput, SeriesPlacement } from "../../../series/types";
7
7
  import { parseOptionSymbol } from "../../../utils/options";
8
8
  import type { SeriesCatalogInstrument } from "./series-catalog";
9
+ import { macroReleaseTopic } from "../shared/macro-releases";
9
10
 
10
11
  export const CHART_COMPOSER_TEMPLATE_ID = "chart-composer-pane";
11
12
  export const DATA_CATALOG_PANE_ID = "data-catalog";
@@ -30,6 +31,8 @@ export interface CatalogSeriesRow {
30
31
  /** The registered expression, `{ticker}` where a symbol goes. */
31
32
  template: string;
32
33
  url?: string;
34
+ /** A limit the publisher sets on the series' data, such as how far back its history goes. */
35
+ limitation?: string;
33
36
  /** Asks for a symbol before charting. */
34
37
  input?: SeriesInput;
35
38
  /** The symbol a row filled in for a typed ticker charts. */
@@ -119,6 +122,7 @@ function rowFromEntry(entry: SeriesCatalogEntry): Omit<CatalogSeriesRow, "order"
119
122
  expression,
120
123
  template: entry.expression,
121
124
  ...(entry.url ? { url: entry.url } : {}),
125
+ ...(entry.limitation ? { limitation: entry.limitation } : {}),
122
126
  ...(entry.input ? { input: entry.input } : {}),
123
127
  ...(entry.placement || entry.lines?.length ? {
124
128
  seriesName: entry.name,
@@ -358,6 +362,7 @@ export function catalogEmptyCopy(
358
362
  ): { title: string; hint?: string } {
359
363
  if (loading) return { title: "Loading catalog…" };
360
364
  const query = searchQuery.trim();
361
- if (query) return { title: `No series matching "${query}"`, hint: "Press / to search." };
365
+ // A PMI or a nowcast is a calendar release, not a series: say where it is rather than search again.
366
+ if (query) return { title: `No series matching "${query}"`, hint: macroReleaseTopic(query)?.paneHint ?? "Press / to search." };
362
367
  return { title: "No series", hint: "Press / to search." };
363
368
  }
@@ -210,7 +210,7 @@ function effectiveSeriesUnitGroup(series: ChartSeriesSpec): string {
210
210
  : getTimeSeriesField(series.source.fieldId)?.unitGroup ?? series.source.fieldId;
211
211
  }
212
212
 
213
- function nextGeneratedPanelId(
213
+ export function nextGeneratedPanelId(
214
214
  spec: Pick<ChartSpec, "panels" | "series" | "studies">,
215
215
  prefix = "panel",
216
216
  ): string {
@@ -39,8 +39,8 @@ function chartResolution(options: HeadlessPaneOptionValues): ChartResolution | n
39
39
  return parseChartResolution(options.chartResolution ?? options.resolution);
40
40
  }
41
41
 
42
- function financialPeriod(value: unknown): SeriesPeriod | null {
43
- return value === "annual" || value === "quarterly" || value === "ttm" ? value : null;
42
+ function financialPeriod(value: unknown, valuation: boolean): SeriesPeriod | null {
43
+ return value === "annual" || value === "quarterly" || value === "ttm" || (valuation && value === "daily") ? value : null;
44
44
  }
45
45
 
46
46
  function mapSecuritySeries(
@@ -81,6 +81,10 @@ export function applyChartComposerCapabilityOptions(
81
81
  next = { ...next, viewport: { ...next.viewport, extendedHours: true } };
82
82
  }
83
83
 
84
+ if (capabilityId === "price-comparison" && options.totalReturn === true) {
85
+ next = { ...next, viewport: { ...next.viewport, totalReturn: true } };
86
+ }
87
+
84
88
  if (PRICE_CAPABILITIES.has(capabilityId) && options.axisMode) {
85
89
  const transform = options.axisMode === "percent" ? "percent" : "raw";
86
90
  next = {
@@ -95,15 +99,15 @@ export function applyChartComposerCapabilityOptions(
95
99
  const graphKind = capabilityId === "fundamental-series"
96
100
  ? "fundamental"
97
101
  : capabilityId === "valuation-series" ? "valuation" : null;
98
- if (graphKind && typeof options.metric === "string") {
99
- const period = financialPeriod(options.period);
102
+ if (graphKind) {
103
+ const period = financialPeriod(options.period, graphKind === "valuation");
100
104
  next = {
101
105
  ...next,
102
106
  series: mapSecuritySeries(next.series, (entry) => ({
103
107
  ...entry,
104
108
  source: entry.source.kind === "security" ? {
105
109
  ...entry.source,
106
- fieldId: `${graphKind}.${options.metric}`,
110
+ ...(typeof options.metric === "string" ? { fieldId: `${graphKind}.${options.metric}` } : {}),
107
111
  ...(period ? { period } : {}),
108
112
  } : entry.source,
109
113
  })),
@@ -4,6 +4,7 @@ import { Box } from "../../../ui";
4
4
  import {
5
5
  DataTableView,
6
6
  QueryBar,
7
+ usePaneNoticeFooter,
7
8
  usePaneTabs,
8
9
  useQueryBarSearch,
9
10
  type DataTableCell,
@@ -11,6 +12,7 @@ import {
11
12
  type DataTableKeyEvent,
12
13
  type DataTableRootKeyContext,
13
14
  } from "../../../components";
15
+ import { usePaneRefreshKey } from "../../../components/data-table/table-pane";
14
16
  import type { PaneProps } from "../../../types/plugin";
15
17
  import { colors } from "../../../theme/colors";
16
18
  import { nextHeaderSort, type SortDirection } from "../../../utils/sort-values";
@@ -118,14 +120,15 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
118
120
  const [sortPreference, setSortPreference] = useState<CatalogSortPreference>(DEFAULT_SORT);
119
121
  const { active: searchFocused, focus: focusSearch, searchProps } = useQueryBarSearch();
120
122
 
121
- const entries = useRegisteredSeries();
123
+ const { entries, loading: catalogLoading, error: catalogError, retry } = useRegisteredSeries();
124
+ usePaneRefreshKey(() => { void retry(); }, { focused, enabled: !searchFocused });
122
125
  const catalogRows = useMemo(() => catalogRowsFromEntries(entries), [entries]);
123
126
  const filter = normalizeCatalogFilter(savedFilter, catalogRows);
124
127
  const tickerQuery = looksLikeCatalogTickerQuery(searchQuery);
125
128
  const { instruments, loading: universeLoading } = useCatalogUniverse(
126
129
  tickerQuery ? searchQuery : "",
127
130
  );
128
- const loading = tickerQuery && universeLoading;
131
+ const loading = catalogLoading || (tickerQuery && universeLoading);
129
132
  const emptyCopy = catalogEmptyCopy(loading, searchQuery);
130
133
 
131
134
  const listedCrypto = useMemo(
@@ -240,6 +243,12 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
240
243
  }
241
244
  }, []);
242
245
 
246
+ usePaneNoticeFooter({
247
+ registrationId: `${DATA_CATALOG_PANE_ID}:notices`,
248
+ focused,
249
+ notices: selectedRow?.limitation ? [`${selectedRow.label}: ${selectedRow.limitation}`] : [],
250
+ });
251
+
243
252
  usePaneStatusLinkFooter({
244
253
  registrationId: DATA_CATALOG_PANE_ID,
245
254
  focused,
@@ -247,6 +256,7 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
247
256
  source: selectedUrl ? selectedRow?.publisher : null,
248
257
  label: "source",
249
258
  loading,
259
+ error: catalogError,
250
260
  hints: [
251
261
  { id: "graph", key: "g", label: "raph", onPress: () => chartSelected(selectedRow), disabled: !selectedRow },
252
262
  { id: "search", key: "/", label: "search", onPress: focusSearch },
@@ -10,7 +10,7 @@ import type {
10
10
  SeriesTimestampMode,
11
11
  SeriesTransform,
12
12
  } from "../../../../time-series/types";
13
- import { hasStudyInputCount, validateChartSpec } from "../../../../time-series/spec";
13
+ import { hasStudyInputCount, isOhlcSeriesStyle, validateChartSpec } from "../../../../time-series/spec";
14
14
  import { isPlainKey } from "../../../../utils/keyboard";
15
15
  import { getSharedRegistry } from "../../../registry";
16
16
  import {
@@ -190,6 +190,7 @@ export function useSeriesEditorController({
190
190
  suggestions: quickAddSuggestions,
191
191
  loading: quickAddLoading,
192
192
  error: quickAddError,
193
+ retry: retryQuickAdd,
193
194
  } = useSeriesCatalogSuggestions({
194
195
  query: quickAddQuery,
195
196
  defaultInstrument,
@@ -414,7 +415,7 @@ export function useSeriesEditorController({
414
415
  : current.panels,
415
416
  series: replaceAt(current.series, selectedIndex, (() => {
416
417
  const currentSeries = current.series[selectedIndex]!;
417
- const ohlcStyle = currentSeries.style === "candles" || currentSeries.style === "ohlc" || currentSeries.style === "hlc";
418
+ const ohlcStyle = isOhlcSeriesStyle(currentSeries.style);
418
419
  return {
419
420
  ...currentSeries,
420
421
  style: transform !== "raw" && ohlcStyle
@@ -638,6 +639,7 @@ export function useSeriesEditorController({
638
639
  quickAddItems,
639
640
  quickAddLoading,
640
641
  quickAddError,
642
+ retryQuickAdd,
641
643
  quickAddQuery,
642
644
  quickAddRef,
643
645
  quickAddSelection,
@@ -74,12 +74,14 @@ function seriesFieldId(series: ChartSeriesSpec): string {
74
74
 
75
75
  function compatiblePeriods(series: ChartSeriesSpec): SeriesPeriod[] {
76
76
  if (series.source.kind !== "security") return [];
77
+ if (series.source.fieldId.startsWith("valuation.") && series.source.fieldId !== "valuation.realizedNtmPE") return ["daily", ...FINANCIAL_PERIODS];
77
78
  return series.source.fieldId.startsWith("market.") ? MARKET_PERIODS : FINANCIAL_PERIODS;
78
79
  }
79
80
 
80
81
  export function supportsSeriesTimestampMode(series: ChartSeriesSpec | null): boolean {
81
82
  return !!series
82
83
  && series.source.kind === "security"
84
+ && series.source.period !== "daily"
83
85
  && isFundamentalFieldId(series.source.fieldId);
84
86
  }
85
87