gloomberb 0.18.3 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (886) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/src/account/checkout-handoff.tsx +225 -0
  6. package/src/account/device-signin-dialog.tsx +2 -2
  7. package/src/account/device-signin.ts +2 -2
  8. package/src/account/upgrade-dialog.tsx +1 -1
  9. package/src/api-client/askg.ts +2 -2
  10. package/src/api-client/auth.ts +2 -2
  11. package/src/api-client/central-bank-rates.ts +6 -0
  12. package/src/api-client/collections.ts +5 -1
  13. package/src/api-client/cot.ts +2 -0
  14. package/src/api-client/crypto-etf-flows.ts +37 -0
  15. package/src/api-client/crypto-markets.ts +60 -0
  16. package/src/api-client/data.ts +84 -5
  17. package/src/api-client/doe.ts +15 -0
  18. package/src/api-client/equity-screener.ts +28 -0
  19. package/src/api-client/exchange-announcements.ts +38 -0
  20. package/src/api-client/fund-facts.ts +39 -0
  21. package/src/api-client/futures-curve.ts +9 -1
  22. package/src/api-client/hiring.ts +301 -0
  23. package/src/api-client/index.ts +22 -5
  24. package/src/api-client/market-discovery.ts +14 -0
  25. package/src/api-client/members.ts +6 -0
  26. package/src/api-client/mna.ts +6 -0
  27. package/src/api-client/paths.ts +18 -1
  28. package/src/api-client/request.ts +21 -4
  29. package/src/api-client/short-side-publications.ts +37 -0
  30. package/src/api-client/socket.ts +64 -4
  31. package/src/api-client/swap-curve.ts +35 -0
  32. package/src/api-client/themes.ts +7 -1
  33. package/src/api-client/types.ts +90 -2
  34. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  35. package/src/app/runtime/desktop-deeplink.ts +5 -5
  36. package/src/app/runtime/plugin-bindings.ts +2 -2
  37. package/src/app/runtime/startup.ts +13 -0
  38. package/src/app/star-prompt/status-line.tsx +2 -2
  39. package/src/architecture/core-builtin-allowlist.json +5 -2
  40. package/src/architecture/ui-literals-allowlist.json +3 -3
  41. package/src/architecture/ui-tokens-allowlist.json +1 -1
  42. package/src/brokers/broker-portfolio-sync.ts +37 -0
  43. package/src/brokers/directory.ts +11 -0
  44. package/src/brokers/logos.ts +3 -1
  45. package/src/brokers/signed-in/adapter.ts +304 -26
  46. package/src/brokers/signed-in/client.ts +14 -2
  47. package/src/brokers/signed-in/connect.ts +10 -2
  48. package/src/brokers/sync-broker-instance.ts +9 -1
  49. package/src/capabilities/chart-series.ts +22 -6
  50. package/src/cli/bank-section.ts +1 -1
  51. package/src/cli/base-converter.ts +23 -14
  52. package/src/cli/central-bank-events.ts +1 -1
  53. package/src/cli/command-options.ts +59 -4
  54. package/src/cli/commands/api.ts +9 -6
  55. package/src/cli/commands/broker.ts +2 -2
  56. package/src/cli/commands/command-utils.ts +2 -2
  57. package/src/cli/commands/crypto-hints.ts +7 -20
  58. package/src/cli/commands/fred-series.ts +4 -2
  59. package/src/cli/commands/keybindings.ts +2 -2
  60. package/src/cli/commands/market.ts +1117 -264
  61. package/src/cli/commands/news-hints.ts +2 -2
  62. package/src/cli/commands/news-search.ts +59 -6
  63. package/src/cli/commands/options-leaps.ts +41 -26
  64. package/src/cli/commands/overview.ts +121 -48
  65. package/src/cli/commands/plugins.ts +9 -9
  66. package/src/cli/commands/remote.ts +13 -10
  67. package/src/cli/commands/search.ts +64 -44
  68. package/src/cli/commands/system.ts +27 -19
  69. package/src/cli/commands/themes.ts +1 -1
  70. package/src/cli/commands/ticker.ts +192 -47
  71. package/src/cli/context.ts +3 -2
  72. package/src/cli/desktop-pane-shot-view.ts +2 -2
  73. package/src/cli/desktop-pane-shot.ts +1 -1
  74. package/src/cli/earnings-calendar.ts +4 -4
  75. package/src/cli/entry.ts +18 -1
  76. package/src/cli/errors.ts +20 -2
  77. package/src/cli/exit-codes.ts +1 -1
  78. package/src/cli/export-source.ts +10 -4
  79. package/src/cli/freshness.ts +2 -8
  80. package/src/cli/fx-forward.ts +130 -0
  81. package/src/cli/fx-pair.ts +10 -9
  82. package/src/cli/glossary.ts +64 -20
  83. package/src/cli/help.ts +19 -13
  84. package/src/cli/history-export.ts +126 -0
  85. package/src/cli/history-rows.ts +196 -43
  86. package/src/cli/index-roots.ts +5 -45
  87. package/src/cli/index.ts +24 -18
  88. package/src/cli/known-gaps.ts +118 -25
  89. package/src/cli/listing-arg.ts +300 -41
  90. package/src/cli/name-entries.ts +30 -18
  91. package/src/cli/native-smoke.ts +2 -0
  92. package/src/cli/not-a-ticker.ts +19 -9
  93. package/src/cli/opentui-libc.ts +5 -0
  94. package/src/cli/options.ts +12 -0
  95. package/src/cli/pane-functions/capabilities.ts +75 -20
  96. package/src/cli/pane-functions/catalog.ts +24 -23
  97. package/src/cli/pane-functions/discovery.ts +1 -1
  98. package/src/cli/pane-functions/dom.ts +10 -7
  99. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  100. package/src/cli/pane-functions/freshness.ts +174 -23
  101. package/src/cli/pane-functions/function-help.ts +66 -27
  102. package/src/cli/pane-functions/headless.ts +24 -11
  103. package/src/cli/pane-functions/index.ts +18 -16
  104. package/src/cli/pane-functions/options.ts +22 -2
  105. package/src/cli/pane-functions/report-notices.ts +12 -4
  106. package/src/cli/pane-functions/report.ts +5 -5
  107. package/src/cli/pane-functions/resolver.ts +47 -10
  108. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  109. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  110. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  111. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  112. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  113. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  114. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  115. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  116. package/src/cli/pane-functions/shot-options.ts +8 -3
  117. package/src/cli/peso-dollar-rates.ts +79 -0
  118. package/src/cli/quote-answer.ts +38 -3
  119. package/src/cli/report-tables.ts +61 -16
  120. package/src/cli/restore-plugins.ts +29 -14
  121. package/src/cli/result.ts +111 -22
  122. package/src/cli/series-search.ts +5 -5
  123. package/src/cli/statement-filings.ts +19 -0
  124. package/src/cli/suffixed-listing-rows.ts +49 -0
  125. package/src/cli/symbol-args.ts +50 -15
  126. package/src/cli/symbol-cells.ts +120 -0
  127. package/src/cli/symbol-list.ts +198 -68
  128. package/src/cli/symbol-rows.ts +131 -25
  129. package/src/cli/ticker-resolution.ts +108 -11
  130. package/src/cli/treasury-yields.ts +5 -5
  131. package/src/cli/types.ts +2 -0
  132. package/src/cli/uncovered-instrument.ts +3 -3
  133. package/src/cli/unknown-command.ts +6 -6
  134. package/src/components/chart/composite/chart-layout.ts +131 -0
  135. package/src/components/chart/composite/composite-chart.tsx +373 -16
  136. package/src/components/chart/composite/interactions.ts +7 -2
  137. package/src/components/chart/composite/legend.tsx +75 -3
  138. package/src/components/chart/composite/levels.ts +5 -0
  139. package/src/components/chart/composite/panel-gestures.ts +41 -0
  140. package/src/components/chart/composite/panel-labels.ts +2 -1
  141. package/src/components/chart/composite/panel-surface.tsx +305 -11
  142. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  143. package/src/components/chart/composite/rasterizer.ts +44 -19
  144. package/src/components/chart/composite/scene.ts +16 -4
  145. package/src/components/chart/composite/text-renderer.ts +48 -21
  146. package/src/components/chart/composite/toolbar.tsx +52 -5
  147. package/src/components/chart/composite/types.ts +13 -0
  148. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  149. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  150. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  151. package/src/components/chart/composite/value-scale.ts +149 -0
  152. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  153. package/src/components/chart/core/pointer.ts +2 -0
  154. package/src/components/chart-table/index.ts +2 -0
  155. package/src/components/chart-table/read.tsx +74 -0
  156. package/src/components/command-bar/commands/collection-list.ts +41 -19
  157. package/src/components/command-bar/commands/collection.ts +9 -3
  158. package/src/components/command-bar/commands/direct/index.ts +1 -1
  159. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  160. package/src/components/command-bar/pane-templates/items.ts +59 -6
  161. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  162. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  163. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  164. package/src/components/command-bar/routes/root/results.ts +18 -4
  165. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  166. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  167. package/src/components/command-bar/routes/root/selection.ts +6 -1
  168. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  169. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  170. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  171. package/src/components/command-bar/selection-runtime.ts +50 -10
  172. package/src/components/command-bar/surface/index.tsx +24 -2
  173. package/src/components/command-bar/view-model.ts +7 -0
  174. package/src/components/command-bar/workflow/broker.ts +2 -2
  175. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  176. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  177. package/src/components/command-bar/workflow/fields.ts +8 -2
  178. package/src/components/command-bar/workflow/ops.ts +18 -4
  179. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  180. package/src/components/command-bar/workflow/submit.ts +3 -2
  181. package/src/components/command-bar/workflow/tickers.ts +5 -1
  182. package/src/components/company-logo.tsx +39 -0
  183. package/src/components/data-table/sections.ts +4 -2
  184. package/src/components/form-modal/confirm.tsx +2 -1
  185. package/src/components/form-modal/request.ts +5 -0
  186. package/src/components/form-modal/routes.ts +4 -1
  187. package/src/components/index.ts +12 -6
  188. package/src/components/layout/header.tsx +7 -6
  189. package/src/components/layout/market-summary.ts +9 -6
  190. package/src/components/layout/pane/capture-status.ts +1 -1
  191. package/src/components/layout/pane/footer/model.ts +11 -5
  192. package/src/components/layout/shell/chrome.ts +19 -6
  193. package/src/components/layout/shell/index.tsx +2 -1
  194. package/src/components/layout/shell/pane/layers.tsx +19 -1
  195. package/src/components/layout/status-bar.tsx +2 -2
  196. package/src/components/market-board/index.tsx +11 -3
  197. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  198. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  199. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  200. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  201. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  202. package/src/components/pane-settings-dialog/value.ts +8 -1
  203. package/src/components/pane-settings-dialog.tsx +44 -13
  204. package/src/components/sign-in-code-panel.tsx +27 -19
  205. package/src/components/ui/column-grid.tsx +48 -4
  206. package/src/components/ui/country-flag-art.tsx +180 -0
  207. package/src/components/ui/country-flag.tsx +118 -12
  208. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  209. package/src/components/ui/data-table/opentui/model.ts +109 -2
  210. package/src/components/ui/data-table/types.ts +1 -1
  211. package/src/components/ui/display.tsx +5 -1
  212. package/src/components/ui/index.ts +3 -1
  213. package/src/components/ui/logo-mark.tsx +11 -2
  214. package/src/components/ui/query-bar.tsx +1 -1
  215. package/src/components/ui/row-notes.ts +79 -0
  216. package/src/core/state/app/layout.ts +4 -4
  217. package/src/data/cached-query.ts +8 -1
  218. package/src/data/config/chart-settings.ts +3 -3
  219. package/src/data/config/home.ts +10 -2
  220. package/src/data/config/layout.ts +4 -1
  221. package/src/data/config/store/node.ts +4 -0
  222. package/src/data/config/store/normalize.ts +13 -3
  223. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  224. package/src/data/json-storage.ts +2 -0
  225. package/src/data/saved-copies.ts +84 -0
  226. package/src/docs/snapshot.json +65 -32
  227. package/src/i18n/es.ts +29 -12
  228. package/src/i18n/ja.ts +29 -12
  229. package/src/i18n/ko.ts +29 -12
  230. package/src/i18n/zh-cn.ts +29 -12
  231. package/src/i18n/zh-tw.ts +29 -12
  232. package/src/layout/desks.ts +1 -1
  233. package/src/layout/launch-layout.ts +1 -1
  234. package/src/layout/pane-manager/floating-actions.ts +5 -3
  235. package/src/layout/pane-manager/floating.ts +43 -1
  236. package/src/layout/pane-manager/index.ts +2 -0
  237. package/src/layout/selected-ticker.ts +74 -0
  238. package/src/market-data/depositary-pair.ts +251 -0
  239. package/src/market-data/futures-board.ts +1 -1
  240. package/src/market-data/futures-contract.ts +124 -40
  241. package/src/market-data/fx-closes.ts +17 -2
  242. package/src/market-data/hooks.tsx +19 -11
  243. package/src/market-data/market/change-basis.ts +49 -7
  244. package/src/market-data/market/freshness.ts +34 -5
  245. package/src/market-data/market/period-return.ts +163 -0
  246. package/src/market-data/market/trading-sessions.ts +13 -0
  247. package/src/market-data/market/year-to-date.ts +8 -13
  248. package/src/market-data/performance.ts +20 -14
  249. package/src/market-data/perpetual-premium.ts +32 -0
  250. package/src/market-data/published-apac-sessions.ts +2 -1
  251. package/src/market-data/published-futures-sessions.ts +69 -0
  252. package/src/market-data/quotes/contributions.ts +5 -1
  253. package/src/market-data/quotes/freshness.ts +42 -0
  254. package/src/market-data/quotes/intraday-bar.ts +37 -0
  255. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  256. package/src/market-data/quotes/resolution.ts +4 -2
  257. package/src/market-data/tax-equivalent.ts +1 -1
  258. package/src/market-data/ticker-price-returns.ts +3 -1
  259. package/src/news/aggregator.ts +5 -1
  260. package/src/news/news-model.ts +4 -0
  261. package/src/news/types.ts +11 -0
  262. package/src/notifications/app-notifier.ts +1 -1
  263. package/src/plugins/auto-update.ts +2 -2
  264. package/src/plugins/builtin/account-management/index.tsx +1 -0
  265. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  266. package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
  267. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  268. package/src/plugins/builtin/alerts/cli.ts +485 -76
  269. package/src/plugins/builtin/alerts/command.ts +5 -10
  270. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  271. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  272. package/src/plugins/builtin/alerts/events.ts +107 -5
  273. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  274. package/src/plugins/builtin/alerts/format.ts +2 -1
  275. package/src/plugins/builtin/alerts/headless.ts +100 -39
  276. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  277. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  278. package/src/plugins/builtin/alerts/index.tsx +45 -18
  279. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  280. package/src/plugins/builtin/alerts/levels.ts +3 -3
  281. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  282. package/src/plugins/builtin/alerts/price.ts +35 -0
  283. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  284. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  285. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  286. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  287. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  288. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  289. package/src/plugins/builtin/alerts/storage.ts +13 -10
  290. package/src/plugins/builtin/alerts/targets.ts +12 -3
  291. package/src/plugins/builtin/analytics/index.tsx +8 -2
  292. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  293. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  294. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  295. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  296. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  297. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  298. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  299. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  300. package/src/plugins/builtin/attention/pane.tsx +6 -2
  301. package/src/plugins/builtin/awards/headless.ts +7 -3
  302. package/src/plugins/builtin/awards/model.ts +18 -0
  303. package/src/plugins/builtin/awards/pane.tsx +6 -3
  304. package/src/plugins/builtin/backtest/headless.ts +3 -3
  305. package/src/plugins/builtin/backtest/rules.ts +41 -5
  306. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  307. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  308. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  309. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  310. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  311. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  312. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  313. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  314. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  315. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  316. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  317. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  318. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  319. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  320. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  321. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  322. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  323. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  324. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  325. package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
  326. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  327. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  328. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  329. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  330. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  331. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  332. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  333. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  334. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  335. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  336. package/src/plugins/builtin/catalysts/model.ts +49 -4
  337. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  338. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  339. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  340. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  341. package/src/plugins/builtin/changelog/index.tsx +1 -0
  342. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  343. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  344. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  345. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  346. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  347. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  348. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  349. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  350. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  351. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  352. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  353. package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
  354. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  355. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  356. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  357. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  358. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  359. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  360. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  361. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  362. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  363. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  364. package/src/plugins/builtin/chat/people.ts +1 -1
  365. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  366. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  367. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  368. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  369. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  370. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  371. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  372. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  373. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  374. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  375. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  376. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  377. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  378. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  379. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  380. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  381. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  382. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  383. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  384. package/src/plugins/builtin/company-attention/client.ts +117 -1
  385. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  386. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  387. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  388. package/src/plugins/builtin/company-attention/model.ts +33 -7
  389. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  390. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  391. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  392. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  393. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  394. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  395. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  396. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  397. package/src/plugins/builtin/composite-plugins.ts +2 -1
  398. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  399. package/src/plugins/builtin/connections/index.ts +1 -0
  400. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  401. package/src/plugins/builtin/correlation/headless.ts +5 -3
  402. package/src/plugins/builtin/cot/headless.ts +28 -6
  403. package/src/plugins/builtin/cot/model.ts +12 -0
  404. package/src/plugins/builtin/cot/pane.tsx +3 -2
  405. package/src/plugins/builtin/cpi/headless.ts +5 -1
  406. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  407. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  408. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  409. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  410. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  411. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  412. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  413. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  414. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  415. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  416. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  417. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  418. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  419. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  420. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  421. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  422. package/src/plugins/builtin/debug/index.tsx +1 -0
  423. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  424. package/src/plugins/builtin/docs/index.tsx +1 -1
  425. package/src/plugins/builtin/docs/pane.tsx +2 -2
  426. package/src/plugins/builtin/docs/targets.ts +1 -1
  427. package/src/plugins/builtin/doe/client.ts +5 -1
  428. package/src/plugins/builtin/doe/headless.ts +12 -6
  429. package/src/plugins/builtin/doe/model.ts +43 -6
  430. package/src/plugins/builtin/doe/pane.tsx +18 -11
  431. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  432. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  433. package/src/plugins/builtin/earnings/board.tsx +253 -50
  434. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  435. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  436. package/src/plugins/builtin/earnings/client.ts +4 -3
  437. package/src/plugins/builtin/earnings/headless.ts +53 -15
  438. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  439. package/src/plugins/builtin/earnings/index.tsx +15 -22
  440. package/src/plugins/builtin/earnings/model.ts +17 -12
  441. package/src/plugins/builtin/earnings/scope.ts +89 -0
  442. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  443. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  444. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  445. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  446. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  447. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  448. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  449. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  450. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  451. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  452. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  453. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  454. package/src/plugins/builtin/econ/index.tsx +112 -25
  455. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  456. package/src/plugins/builtin/econ/types.ts +32 -1
  457. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  458. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  459. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  460. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  461. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  462. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  463. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  464. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  465. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  466. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  467. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  468. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  469. package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
  470. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  471. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  472. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  473. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  474. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  475. package/src/plugins/builtin/exposure/headless.ts +51 -6
  476. package/src/plugins/builtin/exposure/index.tsx +28 -2
  477. package/src/plugins/builtin/exposure/model.ts +7 -0
  478. package/src/plugins/builtin/exposure/pane.tsx +6 -1
  479. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  480. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  481. package/src/plugins/builtin/futures/model.ts +10 -9
  482. package/src/plugins/builtin/futures/returns.ts +8 -36
  483. package/src/plugins/builtin/futures/table.tsx +1 -1
  484. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  485. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  486. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  487. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  488. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  489. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  490. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  491. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  492. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  493. package/src/plugins/builtin/gpu/headless.ts +9 -4
  494. package/src/plugins/builtin/help/index.tsx +13 -3
  495. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  496. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  497. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  498. package/src/plugins/builtin/holders/client.ts +13 -1
  499. package/src/plugins/builtin/holders/format.ts +28 -17
  500. package/src/plugins/builtin/holders/headless.ts +46 -7
  501. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  502. package/src/plugins/builtin/holders/pane.tsx +79 -15
  503. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  504. package/src/plugins/builtin/holders/table-model.ts +2 -1
  505. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  506. package/src/plugins/builtin/insider/headless.ts +1 -1
  507. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  508. package/src/plugins/builtin/insider/signals.tsx +1 -1
  509. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  510. package/src/plugins/builtin/iv-history/client.ts +20 -0
  511. package/src/plugins/builtin/iv-history/headless.ts +4 -4
  512. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  513. package/src/plugins/builtin/iv-history/model.ts +13 -4
  514. package/src/plugins/builtin/iv-history/series.ts +3 -1
  515. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  516. package/src/plugins/builtin/jobs/model.ts +4 -15
  517. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  518. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  519. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  520. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  521. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  522. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  523. package/src/plugins/builtin/macro-day/model.ts +29 -8
  524. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  525. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  526. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  527. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  528. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  529. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  530. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  531. package/src/plugins/builtin/market-movers/client.ts +33 -19
  532. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  533. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  534. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  535. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  536. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  537. package/src/plugins/builtin/market-movers/table.ts +4 -1
  538. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  539. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  540. package/src/plugins/builtin/members/headless.ts +6 -5
  541. package/src/plugins/builtin/members/pane.tsx +11 -4
  542. package/src/plugins/builtin/mna/client.ts +1 -0
  543. package/src/plugins/builtin/mna/detail.tsx +20 -32
  544. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  545. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  546. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  547. package/src/plugins/builtin/mna/headless.ts +6 -13
  548. package/src/plugins/builtin/mna/model.ts +93 -15
  549. package/src/plugins/builtin/mna/pane.tsx +5 -4
  550. package/src/plugins/builtin/news/headless.ts +12 -6
  551. package/src/plugins/builtin/news/index.tsx +10 -1
  552. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  553. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  554. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  555. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  556. package/src/plugins/builtin/notes/cli.ts +49 -14
  557. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  558. package/src/plugins/builtin/options/carry.ts +2 -2
  559. package/src/plugins/builtin/options/index.tsx +1 -1
  560. package/src/plugins/builtin/options/view.tsx +10 -10
  561. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  562. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  563. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  564. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  565. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  566. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  567. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  568. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  569. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  570. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  571. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  572. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  573. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  574. package/src/plugins/builtin/perps/freshness.ts +8 -5
  575. package/src/plugins/builtin/perps/headless.ts +3 -1
  576. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  577. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  578. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  579. package/src/plugins/builtin/perps/pane.tsx +36 -17
  580. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  581. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  582. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  583. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  584. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  585. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  586. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  587. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  588. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  589. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  590. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  591. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  592. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  593. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  594. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  595. package/src/plugins/builtin/power/client.ts +4 -1
  596. package/src/plugins/builtin/power/evidence.ts +22 -7
  597. package/src/plugins/builtin/power/gas.tsx +5 -1
  598. package/src/plugins/builtin/power/pane.tsx +8 -1
  599. package/src/plugins/builtin/power/prices.tsx +10 -3
  600. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  601. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  602. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  603. package/src/plugins/builtin/research/event-model.ts +3 -1
  604. package/src/plugins/builtin/research/event-sources.ts +12 -4
  605. package/src/plugins/builtin/research/index.tsx +2 -1
  606. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  607. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  608. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  609. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  610. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  611. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  612. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  613. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  614. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  615. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  616. package/src/plugins/builtin/sec/forms.ts +13 -0
  617. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  618. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  619. package/src/plugins/builtin/sec/headless.ts +85 -8
  620. package/src/plugins/builtin/sec/index.tsx +58 -12
  621. package/src/plugins/builtin/sectors/client.ts +2 -1
  622. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  623. package/src/plugins/builtin/series-inventory.ts +2 -0
  624. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  625. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  626. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  627. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  628. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  629. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  630. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  631. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  632. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  633. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  634. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  635. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  636. package/src/plugins/builtin/short-interest/client.ts +2 -0
  637. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  638. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  639. package/src/plugins/builtin/short-interest/model.ts +70 -19
  640. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  641. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  642. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  643. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  644. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  645. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  646. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  647. package/src/plugins/builtin/short-interest/types.ts +9 -0
  648. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  649. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  650. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  651. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  652. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  653. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  654. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  655. package/src/plugins/builtin/themes/headless.ts +8 -5
  656. package/src/plugins/builtin/themes/model.ts +14 -4
  657. package/src/plugins/builtin/themes/pane.tsx +24 -5
  658. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  659. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  660. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  661. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  662. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  663. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  664. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  665. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  666. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  667. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  668. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  669. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  670. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  671. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  672. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  673. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  674. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  675. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  676. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  677. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  678. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  679. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  680. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  681. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  682. package/src/plugins/builtin/vol-surface/client.ts +5 -4
  683. package/src/plugins/builtin/vol-surface/headless.ts +12 -3
  684. package/src/plugins/builtin/vol-surface/model.ts +4 -2
  685. package/src/plugins/builtin/volatility/model.ts +5 -10
  686. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  687. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  688. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  689. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  690. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  691. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  692. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  693. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  694. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  695. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  696. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  697. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  698. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  699. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  700. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  701. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  702. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  703. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  704. package/src/plugins/bundle.ts +1 -1
  705. package/src/plugins/catalog-browser.ts +2 -1
  706. package/src/plugins/compat.ts +3 -3
  707. package/src/plugins/dependencies.ts +75 -14
  708. package/src/plugins/extracted-plugins.ts +132 -34
  709. package/src/plugins/host-link.ts +149 -34
  710. package/src/plugins/installer.ts +35 -10
  711. package/src/plugins/loader.ts +206 -38
  712. package/src/plugins/manager-node.ts +2 -2
  713. package/src/plugins/marketplace/deactivation.ts +22 -0
  714. package/src/plugins/marketplace/model.ts +2 -2
  715. package/src/plugins/marketplace/packs.ts +1 -1
  716. package/src/plugins/ownership.ts +1 -1
  717. package/src/plugins/peer-retry.ts +155 -0
  718. package/src/plugins/registry/contributions.ts +3 -1
  719. package/src/plugins/registry/index.ts +4 -3
  720. package/src/plugins/registry/plugin-state.ts +3 -0
  721. package/src/plugins/seed-notice.ts +20 -0
  722. package/src/plugins/shortcut-argument.ts +39 -0
  723. package/src/portfolio/allocation.ts +1 -1
  724. package/src/portfolio/collection-name.ts +31 -0
  725. package/src/portfolio/column-values.ts +10 -8
  726. package/src/portfolio/cost-fx.ts +296 -19
  727. package/src/portfolio/manual-lots.ts +75 -0
  728. package/src/portfolio/mutations.ts +60 -22
  729. package/src/portfolio/suffixed-listings.ts +209 -0
  730. package/src/portfolio/totals-currency.ts +24 -0
  731. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  732. package/src/public/time-series.ts +11 -8
  733. package/src/remote/schema.ts +1 -1
  734. package/src/renderers/browser/config-host.ts +3 -0
  735. package/src/renderers/browser/main.tsx +23 -3
  736. package/src/renderers/dom/boot-frame-page.ts +187 -0
  737. package/src/renderers/dom/boot-frame.ts +237 -0
  738. package/src/renderers/dom/build-assets.ts +46 -8
  739. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  740. package/src/renderers/dom/host/ascii-text.ts +16 -2
  741. package/src/renderers/dom/host/box.tsx +43 -2
  742. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  743. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  744. package/src/renderers/dom/host/image-surface.tsx +49 -0
  745. package/src/renderers/dom/host/media-surface.tsx +24 -18
  746. package/src/renderers/dom/host/mouse.ts +30 -0
  747. package/src/renderers/dom/host/size-observer.ts +1 -1
  748. package/src/renderers/dom/host/style.ts +1 -1
  749. package/src/renderers/dom/styles.css +76 -0
  750. package/src/renderers/dom/test-utils.tsx +2 -1
  751. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  752. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  753. package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
  754. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  755. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  756. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  757. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  758. package/src/renderers/electrobun/bun/index.ts +11 -1
  759. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  760. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  761. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  762. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  763. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  764. package/src/renderers/electrobun/view/config-host.ts +3 -0
  765. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  766. package/src/renderers/electrobun/view/main.tsx +30 -4
  767. package/src/renderers/electrobun/view/news-source.ts +5 -5
  768. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  769. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  770. package/src/renderers/opentui/browser-open.ts +88 -0
  771. package/src/renderers/opentui/host.tsx +5 -14
  772. package/src/renderers/opentui/image/loader.ts +3 -2
  773. package/src/renderers/opentui/native-smoke.ts +10 -1
  774. package/src/renderers/opentui/pane-image/index.ts +2 -1
  775. package/src/renderers/opentui/render-lib.ts +253 -0
  776. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  777. package/src/renderers/opentui/start.tsx +1 -1
  778. package/src/renderers/share/layout-view.tsx +2 -2
  779. package/src/renderers/share/main.tsx +4 -4
  780. package/src/renderers/share/view.tsx +1 -1
  781. package/src/series/resolve.ts +22 -6
  782. package/src/series/standalone.ts +30 -2
  783. package/src/series/types.ts +8 -1
  784. package/src/shares/api.ts +4 -1
  785. package/src/shares/pane.ts +1 -1
  786. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  787. package/src/sources/gloomberb-cloud/index.ts +32 -16
  788. package/src/sources/gloomberb-cloud/news.ts +39 -0
  789. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  790. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  791. package/src/sources/listing-symbols.ts +37 -0
  792. package/src/sources/provider-errors.ts +16 -2
  793. package/src/sources/provider-router/financial-routes.ts +21 -3
  794. package/src/sources/provider-router/financials.ts +15 -2
  795. package/src/sources/provider-router/history.ts +30 -8
  796. package/src/sources/provider-router/primary.ts +1 -1
  797. package/src/state/app/bootstrap.ts +23 -0
  798. package/src/state/hooks/inline-tickers.ts +30 -5
  799. package/src/sync/controller.ts +1 -1
  800. package/src/sync/core-contributors.ts +46 -14
  801. package/src/team/collections-sync.ts +2 -1
  802. package/src/team/collections.ts +178 -17
  803. package/src/telemetry/crash-reports.ts +17 -4
  804. package/src/test-support/builtin-panes.ts +1 -1
  805. package/src/theme/colors.ts +3 -30
  806. package/src/theme/ui-tokens.ts +37 -1
  807. package/src/tickers/company-name-listing.ts +210 -33
  808. package/src/tickers/index-roots.ts +47 -0
  809. package/src/tickers/instrument-label.ts +5 -1
  810. package/src/tickers/metadata.ts +10 -0
  811. package/src/tickers/perpetual-listing.ts +5 -2
  812. package/src/tickers/search/home-listing.ts +75 -0
  813. package/src/tickers/search/index.ts +76 -27
  814. package/src/tickers/search/ranking.ts +54 -4
  815. package/src/tickers/search/upsert.ts +29 -0
  816. package/src/tickers/terminal-codes.ts +416 -40
  817. package/src/time-series/bar-aggregation.ts +243 -0
  818. package/src/time-series/base-series.ts +307 -0
  819. package/src/time-series/chart-bounds.ts +349 -0
  820. package/src/time-series/chart-seed.ts +142 -0
  821. package/src/time-series/economic.ts +5 -0
  822. package/src/time-series/fundamentals.ts +18 -3
  823. package/src/time-series/history-acquisition.ts +499 -0
  824. package/src/time-series/leverage.ts +100 -0
  825. package/src/time-series/market-resolution.ts +4 -2
  826. package/src/time-series/market.ts +2 -1
  827. package/src/time-series/price-comparison.ts +175 -30
  828. package/src/time-series/range.ts +9 -1
  829. package/src/time-series/resolution.ts +174 -16
  830. package/src/time-series/resolve-context.ts +157 -0
  831. package/src/time-series/resolve.ts +126 -1577
  832. package/src/time-series/series-name.ts +38 -0
  833. package/src/time-series/series-presentation.ts +208 -0
  834. package/src/time-series/spec.ts +11 -6
  835. package/src/time-series/studies.ts +109 -12
  836. package/src/time-series/tail-reconcile.ts +121 -0
  837. package/src/time-series/types.ts +29 -2
  838. package/src/time-series/use-chart-resolution.ts +4 -5
  839. package/src/types/broker.ts +10 -0
  840. package/src/types/config.ts +14 -0
  841. package/src/types/data-provider.ts +14 -0
  842. package/src/types/exchange-rate.ts +6 -0
  843. package/src/types/financials.ts +104 -7
  844. package/src/types/headless.ts +76 -6
  845. package/src/types/instrument.ts +3 -0
  846. package/src/types/plugin.ts +65 -8
  847. package/src/types/price-history.ts +2 -0
  848. package/src/types/ticker.ts +13 -0
  849. package/src/types/trading.ts +59 -1
  850. package/src/ui/ascii-font.ts +13 -1
  851. package/src/ui/host.tsx +6 -1
  852. package/src/updater/command-names.ts +175 -0
  853. package/src/updater/index.ts +10 -5
  854. package/src/utils/calendar-date.ts +32 -15
  855. package/src/utils/cash-runway.ts +241 -0
  856. package/src/utils/central-banks.ts +42 -0
  857. package/src/utils/cli-output.ts +259 -80
  858. package/src/utils/contract-month.ts +16 -0
  859. package/src/utils/crypto-pair.ts +61 -3
  860. package/src/utils/currency-units.ts +29 -0
  861. package/src/utils/datetime-format.ts +10 -0
  862. package/src/utils/debug-log.ts +1 -1
  863. package/src/utils/decimal-comma.ts +39 -6
  864. package/src/utils/exchange-announcements.ts +71 -0
  865. package/src/utils/exchange-rate-snapshot.ts +10 -0
  866. package/src/utils/financial-statements.ts +83 -4
  867. package/src/utils/format.ts +34 -16
  868. package/src/utils/fundamentals.ts +150 -34
  869. package/src/utils/fx-market-hours.ts +10 -1
  870. package/src/utils/latest-financial-period.ts +8 -0
  871. package/src/utils/linux-libc.ts +54 -0
  872. package/src/utils/market-capitalization.ts +111 -15
  873. package/src/utils/max-drawdown.ts +64 -0
  874. package/src/utils/network-failure.ts +83 -0
  875. package/src/utils/option-expiry.ts +139 -7
  876. package/src/utils/price-earnings.ts +11 -5
  877. package/src/utils/price-history.ts +18 -8
  878. package/src/utils/price-window.ts +131 -0
  879. package/src/utils/release-date.ts +47 -0
  880. package/src/utils/sec.ts +3 -0
  881. package/src/utils/throttled-fetch.ts +11 -4
  882. package/src/utils/trailing-eps.ts +67 -0
  883. package/src/utils/typed-text.ts +21 -0
  884. package/src/utils/utc-time.ts +24 -1
  885. package/src/version.ts +6 -0
  886. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -40,15 +40,16 @@ function noMoveNotice(symbols: readonly string[], names: number): string {
40
40
  }
41
41
 
42
42
  /**
43
- * When the board's figures are from, and whose sessions they follow: outside
43
+ * When the board's figures are from, and whose sessions they follow: when its
44
+ * prices printed, from a server that says (`pricesAsOf`). Otherwise, outside
44
45
  * the regular session the tiles are the completed session's, so the board is
45
46
  * as of that session's close (its date, from a server that does not send the
46
- * close), not when the snapshot was put together; while it trades, the
47
- * snapshot time.
47
+ * close); while it trades, the snapshot time, which is later than its prices.
48
48
  */
49
- function boardObservation(board: Pick<MarketHeatmapBoard, "fetchedAt" | "regularSessionDate" | "regularSessionClosedAt">) {
49
+ function boardObservation(board: Pick<MarketHeatmapBoard, "fetchedAt" | "regularSessionDate" | "regularSessionClosedAt" | "pricesAsOf">) {
50
50
  const closedAt = board.regularSessionDate ? board.regularSessionClosedAt : null;
51
- const asOf = typeof closedAt === "number" && closedAt > 0 ? new Date(closedAt).toISOString()
51
+ const pricedAt = typeof board.pricesAsOf === "number" && board.pricesAsOf > 0 ? board.pricesAsOf : closedAt;
52
+ const asOf = typeof pricedAt === "number" && pricedAt > 0 ? new Date(pricedAt).toISOString()
52
53
  : board.regularSessionDate || new Date(board.fetchedAt).toISOString();
53
54
  return { asOf, sessionExchange: "NYSE" };
54
55
  }
@@ -101,7 +102,7 @@ export const marketHeatmapHeadless: HeadlessPaneDefinition<"rows"> = {
101
102
  aliases: ["HM", "heatmap"],
102
103
  dataRequirements: ["Gloom Cloud market heatmap snapshot"],
103
104
  limitations: [
104
- "The snapshot the pane starts from, refreshed about once a minute; the pane's live-streamed colors are not in the report.",
105
+ "The snapshot the pane starts from: real-time with Pro, fifteen minutes behind otherwise; the pane's live-streamed colors are not in the report.",
105
106
  "Sizes, shares and the weighted move use market cap (net assets for ETFs), not the pane's tile area, which follows its Size by setting (the day's move by default).",
106
107
  ],
107
108
  },
@@ -129,6 +130,8 @@ export const marketHeatmapHeadless: HeadlessPaneDefinition<"rows"> = {
129
130
  columns: columns(universe, groupBy, flat),
130
131
  rows: groups.map((summary) => projectRow(summary, groupBy, flat)),
131
132
  complete: !result.stale && covered,
133
+ // A Pro account's board is priced from a live read.
134
+ freshness: { status: result.access === "realtime" ? "live" : "delayed", tradingDayMarket: "US" },
132
135
  unavailableSymbols: covered ? [] : noMove,
133
136
  metadata: {
134
137
  universe,
@@ -48,6 +48,7 @@ import {
48
48
  MARKET_HEATMAP_REQUEST_COUNT,
49
49
  MARKET_HEATMAP_UNIVERSES,
50
50
  fetchMarketHeatmap,
51
+ heatmapCheckIntervalMs,
51
52
  resetMarketHeatmapCache,
52
53
  type MarketHeatmapBoard,
53
54
  type MarketHeatmapUniverseId,
@@ -102,7 +103,6 @@ import {
102
103
 
103
104
  const NO_ASSETS: HeatmapBoardAsset[] = [];
104
105
  const NO_TARGETS: QuoteSubscriptionTarget[] = [];
105
- const SNAPSHOT_REFRESH_MS = 60_000;
106
106
  const LAYOUT_THROTTLE_MS = 5_000;
107
107
  /** A size change below this share of a tile's area is not worth moving it. */
108
108
  const LAYOUT_TOLERANCE = 0.005;
@@ -631,8 +631,8 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
631
631
  // Ages the last check that succeeded, not the snapshot, which the server can
632
632
  // hand back unchanged long after it was put together.
633
633
  const checked = useUpdatedAgo(shownBoard?.checkedAt ?? null);
634
- // The snapshot carries sizes and every name the stream does not; the server caches it for a minute.
635
- useAutoRefresh(board?.checkedAt ?? null, autoRefresh, { intervalMs: SNAPSHOT_REFRESH_MS });
634
+ // The snapshot carries sizes and every name the stream does not: a minute on the server, a quarter of one real-time.
635
+ useAutoRefresh(board?.checkedAt ?? null, autoRefresh, { intervalMs: heatmapCheckIntervalMs(board) });
636
636
 
637
637
  usePaneStatusFooter({ registrationId: "market-heatmap-retained", stale: hasBoard && stale && !portfolioTab });
638
638
  usePaneNoticeFooter({
@@ -85,16 +85,18 @@ const isTimestamp = (value: number | null | undefined): value is number =>
85
85
  * the largest names it holds, the completed regular session it shows outside
86
86
  * that session, the time its figures are as of, in New York time, dated when
87
87
  * that day is not the session's (or, while the session trades, today's), and
88
- * when this client last checked, which is a separate figure. A board of a
89
- * completed session is as of that session's close (`regularSessionClosedAt`);
90
- * otherwise, or from a server that does not say, the time is when the server
91
- * put the snapshot together. A footer narrower than `maxWidth` loses the check
88
+ * when this client last checked, which is a separate figure. A board is as of
89
+ * when its prices printed (`pricesAsOf`), a board of a completed session from
90
+ * a server that gives only its close as of that close
91
+ * (`regularSessionClosedAt`); otherwise the time is when the server put the
92
+ * snapshot together, at least fifteen minutes after its prices, and says so.
93
+ * A footer narrower than `maxWidth` loses the check
92
94
  * first, then that time, then the session; after a failed refresh (`failed`)
93
95
  * the age of the last good check outlasts the time. Null when not even the
94
96
  * count fits.
95
97
  */
96
98
  export function heatmapBoardCaption(
97
- board: { topCount: number; fetchedAt: number; regularSessionDate?: string | null; regularSessionClosedAt?: number | null },
99
+ board: { topCount: number; fetchedAt: number; regularSessionDate?: string | null; regularSessionClosedAt?: number | null; pricesAsOf?: number | null },
98
100
  { now, checked = null, failed = false, maxWidth = Number.POSITIVE_INFINITY }:
99
101
  { now: number; checked?: string | null; failed?: boolean; maxWidth?: number },
100
102
  ): string | null {
@@ -103,12 +105,13 @@ export function heatmapBoardCaption(
103
105
  const parts: Array<{ text: string; rank: number }> = [{ text: `top ${board.topCount}`, rank: 0 }];
104
106
  if (sessionDate) parts.push({ text: `${dayLabel(sessionDate)} session`, rank: 1 });
105
107
  const closedAt = sessionDate && isTimestamp(board.regularSessionClosedAt) ? board.regularSessionClosedAt : null;
106
- const time = closedAt ?? (isTimestamp(board.fetchedAt) ? board.fetchedAt : null);
108
+ const pricedAt = isTimestamp(board.pricesAsOf) ? board.pricesAsOf : closedAt;
109
+ const time = pricedAt ?? (isTimestamp(board.fetchedAt) ? board.fetchedAt : null);
107
110
  if (time != null) {
108
111
  const { hour, minute } = zonedDateTimeParts(time, NEW_YORK);
109
112
  const clock = `${twoDigits(hour)}:${twoDigits(minute)} ET`;
110
113
  const day = zonedDateKey(time, NEW_YORK);
111
- const text = `${closedAt != null ? "as of" : "snapshot"} ${day === (sessionDate ?? zonedDateKey(now, NEW_YORK)) ? clock : `${dayLabel(day)} ${clock}`}`;
114
+ const text = `${pricedAt != null ? "as of" : "snapshot"} ${day === (sessionDate ?? zonedDateKey(now, NEW_YORK)) ? clock : `${dayLabel(day)} ${clock}`}`;
112
115
  parts.push({ text, rank: failed ? 3 : 2 });
113
116
  }
114
117
  if (checked) parts.push({ text: `checked ${checked}`, rank: failed ? 2 : 3 });
@@ -18,7 +18,8 @@ import {
18
18
  } from "./model";
19
19
  import {
20
20
  fetchPreferredMarketMovers,
21
- fetchTrending,
21
+ fetchTrendingResult,
22
+ type CachedResult,
22
23
  type MarketMoversResult,
23
24
  type PreferredMoversOptions,
24
25
  type TrendingSymbol,
@@ -30,6 +31,8 @@ export interface MarketMoverTabResult extends MarketMoversResult {
30
31
  quotes: MoverQuote[];
31
32
  /** What the list is ranked by; absent for trending, which keeps its source's order. */
32
33
  rankedBy?: MoverRanking;
34
+ /** Requested trending names whose quotes did not load. */
35
+ unavailableSymbols?: string[];
33
36
  }
34
37
 
35
38
  /** Rows a list shows. */
@@ -46,29 +49,31 @@ export interface MarketMoverTabDependencies {
46
49
  count: number,
47
50
  options?: PreferredMoversOptions,
48
51
  ): Promise<MarketMoversResult>;
49
- fetchTrending(count: number, options?: { forceRefresh?: boolean }): Promise<TrendingSymbol[]>;
52
+ fetchTrending(count: number, options?: { forceRefresh?: boolean }): Promise<CachedResult<TrendingSymbol[]>>;
50
53
  }
51
54
 
52
55
  const defaultDependencies: MarketMoverTabDependencies = {
53
56
  fetchPreferred: (category, count, options) => fetchPreferredMarketMovers(category, count, options),
54
- fetchTrending: (count, options) => fetchTrending(count, undefined, options),
57
+ fetchTrending: (count, options) => fetchTrendingResult(count, undefined, options),
55
58
  };
56
59
 
57
60
  async function hydrateTrending(
58
61
  trending: readonly TrendingSymbol[],
59
62
  provider: DataProvider | null,
60
- ): Promise<MoverQuote[]> {
61
- const symbols = trending.slice(0, 25).map(({ symbol }) => symbol);
63
+ ): Promise<Pick<MarketMoverTabResult, "quotes" | "unavailableSymbols">> {
64
+ const symbols = trending.slice(0, LIST_ROWS).map(({ symbol }) => symbol);
62
65
  const bySymbol = new Map<string, MoverQuote>();
63
- if (!provider) return [];
64
- if (provider.getQuotesBatch) {
65
- const results = await provider.getQuotesBatch(
66
- symbols.map((symbol) => ({ symbol, exchange: "" })),
67
- ).catch(logFailure("market-movers", "Trending quote batch failed", []));
68
- for (const result of results) {
69
- if (result.quote) bySymbol.set(result.target.symbol, screenerQuoteFromQuote(result.target.symbol, result.quote));
66
+ if (symbols.length === 0) return { quotes: [] };
67
+ if (provider?.getQuotesBatch) {
68
+ try {
69
+ const results = await provider.getQuotesBatch(symbols.map((symbol) => ({ symbol, exchange: "" })));
70
+ for (const result of results) {
71
+ if (result.quote) bySymbol.set(result.target.symbol, screenerQuoteFromQuote(result.target.symbol, result.quote));
72
+ }
73
+ } catch (error) {
74
+ logFailure("market-movers", "Trending quote batch failed")(error);
70
75
  }
71
- } else {
76
+ } else if (provider) {
72
77
  await Promise.all(symbols.map(async (symbol) => {
73
78
  try {
74
79
  const quote = await provider.getQuote(symbol, "");
@@ -78,10 +83,18 @@ async function hydrateTrending(
78
83
  }
79
84
  }));
80
85
  }
81
- return symbols.flatMap((symbol) => {
82
- const quote = bySymbol.get(symbol);
83
- return quote ? [quote] : [];
84
- });
86
+ const unavailableSymbols = [...new Set(symbols.filter((symbol) => !bySymbol.has(symbol)))];
87
+ return {
88
+ quotes: symbols.flatMap((symbol) => {
89
+ const quote = bySymbol.get(symbol);
90
+ return quote ? [quote] : [];
91
+ }),
92
+ ...(unavailableSymbols.length ? { unavailableSymbols } : {}),
93
+ };
94
+ }
95
+
96
+ export function marketMoverQuoteError(result: Pick<MarketMoverTabResult, "unavailableSymbols">): string | null {
97
+ return result.unavailableSymbols?.length ? `Quotes unavailable: ${result.unavailableSymbols.join(", ")}.` : null;
85
98
  }
86
99
 
87
100
  export async function loadMarketMoverTab(
@@ -93,11 +106,12 @@ export async function loadMarketMoverTab(
93
106
  const { basis, ...fetchOptions } = options ?? {};
94
107
  if (tab === "trending") {
95
108
  const trending = await dependencies.fetchTrending(LIST_ROWS, fetchOptions);
109
+ const hydrated = await hydrateTrending(trending.data, provider);
96
110
  return {
97
111
  tab,
98
- quotes: await hydrateTrending(trending, provider),
112
+ ...hydrated,
99
113
  source: "gloom",
100
- stale: false,
114
+ stale: trending.stale || !!hydrated.unavailableSymbols?.length,
101
115
  };
102
116
  }
103
117
  const category = CATEGORY_MAP[tab];
@@ -9,7 +9,7 @@ import type {
9
9
  CloudSessionMoversPayload,
10
10
  CloudSessionMoversSide,
11
11
  } from "../../../api-client/market-movers";
12
- import { loadMarketMoverTab, loadSessionMovers, type MarketMoverTabResult } from "./client";
12
+ import { loadMarketMoverTab, loadSessionMovers, marketMoverQuoteError, type MarketMoverTabResult } from "./client";
13
13
  import { createRows, fiftyTwoWeekPositionPercent, formatMoverPrice, MOVER_RANKING_LABELS, moverExtendedSessions, moverReferencePrice, type MarketMoverRow, type ScreenerTabId, type TabId } from "./model";
14
14
  import { EXTENDED_SESSION_LABELS, type ExtendedSession } from "../../../market-data/market/status";
15
15
  import type { HeadlessPaneColumn } from "../../../types/headless";
@@ -98,7 +98,7 @@ export function createMarketMoversHeadless(
98
98
  ): HeadlessPaneDefinition<"rows"> {
99
99
  return {
100
100
  shape: "rows",
101
- // A screener snapshot, not a real-time feed; rows keep the time of their own last price.
101
+ // The delayed lists unless the list says it is real-time; rows keep the time of their own last price.
102
102
  freshness: { status: "delayed" },
103
103
  argument: { kind: "none" },
104
104
  options: [{
@@ -145,6 +145,8 @@ export function createMarketMoversHeadless(
145
145
  events: item.catalysts.map((catalyst) => CATALYST_LABEL[catalyst] ?? catalyst).join(" "),
146
146
  })),
147
147
  metadata: { list: tab, side, session: payload.session, phase: payload.phase, asOf: payload.asOf, stale: payload.stale === true },
148
+ // A Pro account's list is the live board; the free one says it is delayed.
149
+ ...(payload.access === "delayed" ? {} : { freshness: { status: "live" as const } }),
148
150
  };
149
151
  }
150
152
  const result = await dependencies.load(args, tab, ctx.marketData);
@@ -165,15 +167,19 @@ export function createMarketMoversHeadless(
165
167
  }));
166
168
  // Beside an extended column, say which move the order follows.
167
169
  const rankedBy = result.rankedBy ?? null;
170
+ const quoteError = marketMoverQuoteError(result);
168
171
  return {
169
172
  ...(extendedSessions.length > 0
170
173
  ? { columns: [...COLUMNS.slice(0, 5), ...extendedSessions.map(extendedColumn), ...COLUMNS.slice(5)] }
171
174
  : {}),
172
175
  rows,
176
+ ...(quoteError ? { complete: false, unavailableSymbols: result.unavailableSymbols, errors: [quoteError] } : {}),
173
177
  ...(rankedBy && rankedBy !== "volume" && extendedSessions.length > 0
174
178
  ? { notes: [`Ranked by ${MOVER_RANKING_LABELS[rankedBy]}.`] }
175
179
  : {}),
176
180
  metadata: { list: tab, source: result.source, stale: result.stale, rankedBy },
181
+ // A Pro account's Gainers, Losers and Most Active are the real-time lists.
182
+ ...(result.source === "cloud" ? { freshness: { status: "live" as const } } : {}),
177
183
  };
178
184
  },
179
185
  };
@@ -1,4 +1,4 @@
1
- import { Box } from "../../../ui";
1
+ import { Box, useUiCapabilities } from "../../../ui";
2
2
  import { nextHeaderSort } from "../../../utils/sort-values";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { DataTableView, EmptyState, usePaneFooter, usePaneTabs, type DataTableKeyEvent } from "../../../components";
@@ -37,7 +37,7 @@ import {
37
37
  type ScreenerTabId,
38
38
  type TabId,
39
39
  } from "./model";
40
- import { loadMarketMoverTab } from "./client";
40
+ import { loadMarketMoverTab, marketMoverQuoteError } from "./client";
41
41
  import { summaryFooterSegments } from "./footer";
42
42
  import { isSessionTab, resolveActiveTab, usSessionAt, type UsSession } from "./session";
43
43
  import { SessionMoversBody } from "./session-body";
@@ -161,7 +161,7 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
161
161
  const [selectedSymbol, setSelectedSymbol] = useState<string | null>(null);
162
162
  const [sortPreference, setSortPreference] = useState<MarketMoverSortPreference>(DEFAULT_SORT_PREFERENCE);
163
163
  const [moversStale, setMoversStale] = useState(false);
164
- const [lastLoadedAt, setLastLoadedAt] = useState<number | null>(null);
164
+ const [lastSuccess, setLastSuccess] = useState<{ tab: ScreenerTabId; at: number } | null>(null);
165
165
 
166
166
  const fetchGenRef = useRef(0);
167
167
 
@@ -226,12 +226,16 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
226
226
  });
227
227
  if (fetchGenRef.current !== gen) return;
228
228
 
229
- setQuotes(result.quotes);
230
- setLoadedTab(tab);
229
+ const quoteError = marketMoverQuoteError(result);
230
+ // A partial list shows only its current rows; a total failure keeps this list's prior rows.
231
+ if (!quoteError || result.quotes.length > 0) {
232
+ setQuotes(result.quotes);
233
+ setLoadedTab(tab);
234
+ if (!options?.background) setSelectedSymbol(null);
235
+ }
231
236
  setMoversStale(result.stale);
232
- if (!options?.background) setSelectedSymbol(null);
233
- setLoadError(null);
234
- setLastLoadedAt(Date.now());
237
+ setLoadError(quoteError);
238
+ if (!quoteError && !result.stale) setLastSuccess({ tab, at: Date.now() });
235
239
  } catch {
236
240
  if (fetchGenRef.current !== gen) return;
237
241
  setMoversStale(true);
@@ -250,7 +254,7 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
250
254
  const backgroundRefresh = useCallback(() => {
251
255
  void loadTab(activeTab, { background: true });
252
256
  }, [activeTab, loadTab]);
253
- useAutoRefresh(lastLoadedAt, backgroundRefresh);
257
+ useAutoRefresh(lastSuccess?.tab === activeTab ? lastSuccess.at : null, backgroundRefresh);
254
258
 
255
259
  const openSymbol = useCallback((row: MarketMoverRow) => {
256
260
  pinTicker(moverKey(row), { floating: true, paneType: TICKER_RESEARCH_PANE_ID, instrument: null });
@@ -262,6 +266,8 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
262
266
  }));
263
267
  }, []);
264
268
 
269
+ const logos = useUiCapabilities().nativePaneChrome === true;
270
+ const renderCell = useCallback((row: MarketMoverRow, column: MarketMoverColumn) => renderMarketMoverCell(row, column, logos), [logos]);
265
271
  const handleTableKeyDown = useCallback((event: DataTableKeyEvent) => (
266
272
  handleRefreshKey(event, () => loadTab(activeTab, { forceRefresh: true }), { stopPropagation: true })
267
273
  ), [activeTab, loadTab]);
@@ -301,7 +307,7 @@ function ScreenerMoversBody({ activeTab, focused, width, summaryQuotes, liveStre
301
307
  onHeaderClick={handleHeaderClick}
302
308
  getItemKey={moverKey}
303
309
  onActivate={openSymbol}
304
- renderCell={renderMarketMoverCell}
310
+ renderCell={renderCell}
305
311
  selectedTextOverridesCellColor
306
312
  emptyStateTitle={loading ? "Loading movers..." : loadError ?? "No movers returned."}
307
313
  emptyContent={loadError ? (
@@ -146,7 +146,7 @@ export interface MarketMoversResult {
146
146
  }
147
147
 
148
148
  export interface PreferredMarketMoverSources {
149
- isCloudEligible(): boolean;
149
+ isCloudEligible(): boolean | Promise<boolean>;
150
150
  fetchCloud(
151
151
  category: CloudMarketScreenerCategory,
152
152
  count: number,
@@ -275,9 +275,19 @@ function cloudScreenerCategory(category: ScreenerCategory): CloudMarketScreenerC
275
275
  return "most-active";
276
276
  }
277
277
 
278
- function isCloudScreenerEligible(): boolean {
278
+ /**
279
+ * Whether the signed-in account reads the real-time lists. A session restored
280
+ * without its account, as the CLI starts from the saved one, is asked for it
281
+ * first, so a Pro account is never handed the delayed lists.
282
+ */
283
+ export function isCloudScreenerEligible(): boolean | Promise<boolean> {
279
284
  const user = apiClient.getCurrentUser();
280
- return apiClient.isVerified() && hasProAccess(user);
285
+ if (user || !apiClient.isSignedIn()) return apiClient.isVerified() && hasProAccess(user);
286
+ return apiClient.ensureVerifiedSession().then((verified) => !!verified && hasProAccess(verified), (error: unknown) => {
287
+ // The delayed lists still load; the failed account check is logged, not shown.
288
+ logFailure("market-movers", "Account check for the real-time lists failed")(error);
289
+ return false;
290
+ });
281
291
  }
282
292
 
283
293
  const defaultPreferredMarketMoverSources: PreferredMarketMoverSources = {
@@ -361,7 +371,9 @@ export async function fetchPreferredMarketMovers(
361
371
  sources: PreferredMarketMoverSources = defaultPreferredMarketMoverSources,
362
372
  ): Promise<MarketMoversResult> {
363
373
  const { metadataWaitMs = MARKET_METADATA_WAIT_MS, ...options } = preferredOptions ?? {};
364
- if (!sources.isCloudEligible()) {
374
+ // Answered at once unless the account has to be asked for, so a loaded account's list starts as soon as before.
375
+ const eligibility = sources.isCloudEligible();
376
+ if (!(typeof eligibility === "boolean" ? eligibility : await eligibility)) {
365
377
  const result = await sources.fetchMarket(category, count, options);
366
378
  return { quotes: rankScreenerQuotes(category, result.data), source: "gloom", stale: result.stale };
367
379
  }
@@ -410,19 +422,28 @@ export function parseTrendingResponse(data: unknown): TrendingSymbol[] {
410
422
  return data.flatMap(q => q && typeof q.symbol === "string" && q.symbol.trim() ? [{ symbol: q.symbol.trim() }] : []);
411
423
  }
412
424
 
413
- export async function fetchTrending(
425
+ export async function fetchTrendingResult(
414
426
  count = 25,
415
427
  api: MarketScreenerApi = screenerApi,
416
428
  options?: FetchCacheOptions,
417
- ): Promise<TrendingSymbol[]> {
429
+ ): Promise<CachedResult<TrendingSymbol[]>> {
418
430
  const load = async () => {
419
431
  const response = await (api.getMarketTrending ?? apiClient.getMarketTrending)(count);
420
432
  if (response.status === "empty") return { data: [], stale: response.stale === true };
421
433
  if (!response.data) throw new Error("Market trends unavailable");
422
434
  return { data: parseTrendingResponse(response.data), stale: response.stale === true };
423
435
  };
424
- if (!shouldUseCache(api, options)) return (await load()).data;
425
- return (await loadCached(`trending:US:count=${count}`, load, options)).data;
436
+ if (!shouldUseCache(api, options)) return load();
437
+ return loadCached(`trending:US:count=${count}`, load, options);
438
+ }
439
+
440
+ /** Array-only reader retained for the overview command. */
441
+ export async function fetchTrending(
442
+ count = 25,
443
+ api: MarketScreenerApi = screenerApi,
444
+ options?: FetchCacheOptions,
445
+ ): Promise<TrendingSymbol[]> {
446
+ return (await fetchTrendingResult(count, api, options)).data;
426
447
  }
427
448
 
428
449
  export const MARKET_SUMMARY_SYMBOLS = ["^GSPC", "^DJI", "^IXIC", "^RUT"] as const;
@@ -14,7 +14,7 @@ import {
14
14
  import { useAutoRefresh } from "../../../react/auto-refresh";
15
15
  import { useLiveQuoteEntries } from "../../../state/hooks/quote-streaming";
16
16
  import { TICKER_RESEARCH_PANE_ID } from "../../../types/config";
17
- import { Box } from "../../../ui";
17
+ import { Box, useUiCapabilities } from "../../../ui";
18
18
  import { publicTickerKey } from "../../../utils/exchanges";
19
19
  import { nextHeaderSort } from "../../../utils/sort-values";
20
20
  import { usePluginPaneState, usePluginTickerActions } from "../../runtime";
@@ -208,6 +208,8 @@ function SessionMoversTable({ view, session, focused, width, summaryQuotes, live
208
208
  const handleHeaderClick = useCallback((columnId: string) => {
209
209
  setSortPreference(nextHeaderSort(sort, columnId as SessionMoverColumn["id"], { resetTo: DEFAULT_SORT }));
210
210
  }, [sort]);
211
+ const logos = useUiCapabilities().nativePaneChrome === true;
212
+ const renderCell = useCallback((row: SessionMoverRow, column: SessionMoverColumn) => renderSessionMoverCell(row, column, logos), [logos]);
211
213
  const handleKeyDown = useCallback((event: DataTableKeyEvent) => (
212
214
  handleRefreshKey(event, () => load({ forceRefresh: true }), { stopPropagation: true })
213
215
  ), [load]);
@@ -243,7 +245,7 @@ function SessionMoversTable({ view, session, focused, width, summaryQuotes, live
243
245
  onHeaderClick={handleHeaderClick}
244
246
  getItemKey={rowKey}
245
247
  onActivate={openRow}
246
- renderCell={renderSessionMoverCell}
248
+ renderCell={renderCell}
247
249
  selectedTextOverridesCellColor
248
250
  emptyStateTitle={emptyTitle}
249
251
  emptyContent={loadError && !payload ? (
@@ -1,5 +1,6 @@
1
1
  import type { CloudSessionMoversCategory } from "../../../api-client/market-movers";
2
2
  import type { DataTableCell, DataTableColumn } from "../../../components";
3
+ import { withCompanyLogo } from "../../../components/company-logo";
3
4
  import { getTableWidth } from "../../../components/ui/table-layout";
4
5
  import { colors, priceColor } from "../../../theme/colors";
5
6
  import { TextAttributes } from "../../../ui";
@@ -60,14 +61,15 @@ function signedPercent(value: number | null): DataTableCell {
60
61
  };
61
62
  }
62
63
 
63
- export function renderSessionMoverCell(row: SessionMoverRow, column: SessionMoverColumn): DataTableCell {
64
+ /** `logos`: the desktop and the web lead each name with the company's logo; the terminal draws none. */
65
+ export function renderSessionMoverCell(row: SessionMoverRow, column: SessionMoverColumn, logos = false): DataTableCell {
64
66
  switch (column.id) {
65
67
  case "rank":
66
68
  return { text: String(row.rank), color: colors.textDim };
67
69
  case "symbol":
68
70
  return { text: row.symbol, color: colors.textBright, attributes: TextAttributes.BOLD };
69
71
  case "name":
70
- return { text: row.name };
72
+ return withCompanyLogo({ text: row.name }, row, logos);
71
73
  case "price":
72
74
  return { text: formatMoverPrice(row.price, row.currency, moverReferencePrice({ ...row, previousClose: row.referenceClose })), value: row.price };
73
75
  case "gapPercent":
@@ -1,4 +1,5 @@
1
1
  import type { DataTableCell } from "../../../components";
2
+ import { withCompanyLogo } from "../../../components/company-logo";
2
3
  import { getTableWidth } from "../../../components/ui/table-layout";
3
4
  import { TextAttributes } from "../../../ui";
4
5
  import { colors, priceColor } from "../../../theme/colors";
@@ -65,9 +66,11 @@ export function buildMarketMoverColumns(width: number, extendedSessions: readonl
65
66
  return [...lead, { id: "name", label: "NAME", width: Math.max(6, nameRoom()), align: "left" }, ...quote, ...trailing];
66
67
  }
67
68
 
69
+ /** `logos`: the desktop and the web lead each name with the company's logo; the terminal draws none. */
68
70
  export function renderMarketMoverCell(
69
71
  row: MarketMoverRow,
70
72
  column: MarketMoverColumn,
73
+ logos = false,
71
74
  ): DataTableCell {
72
75
  switch (column.id) {
73
76
  case "rank":
@@ -79,7 +82,7 @@ export function renderMarketMoverCell(
79
82
  attributes: TextAttributes.BOLD,
80
83
  };
81
84
  case "name":
82
- return { text: row.name };
85
+ return withCompanyLogo({ text: row.name }, row, logos);
83
86
  case "price":
84
87
  return { text: formatMoverPrice(row.price, row.currency, moverReferencePrice(row)) };
85
88
  case "changePercent":
@@ -74,7 +74,9 @@ function projectValuationHeadlessBundle(
74
74
  richPercentile: view.richPercentile,
75
75
  richSigma: view.richSigma,
76
76
  historyStart: view.historyStart,
77
+ // The first day of the period the reading covers; the report names the period, not that day.
77
78
  asOf: view.asOf,
79
+ ...(view.periodicity ? { periodicity: view.periodicity } : {}),
78
80
  stale: view.observationStale,
79
81
  }));
80
82
 
@@ -9,6 +9,8 @@ import {
9
9
  type ZoneHit,
10
10
  } from "./defs";
11
11
  import { historySpan, type HistorySpan } from "../shared/history-span";
12
+ import { periodsPerYear } from "../shared/stat-transform";
13
+ import { periodStartPeriodicity } from "../../../utils/release-date";
12
14
  import { fitTrend, sigmaVsTrend, trendAt, type TrendFit } from "../shared/trend";
13
15
 
14
16
  const MS_PER_DAY = 86_400_000;
@@ -64,6 +66,8 @@ export interface IndicatorViewModel {
64
66
  */
65
67
  historyStart: string | null;
66
68
  asOf: string;
69
+ /** How often the indicator is read when `asOf` is the first day of its period (Shiller's monthly CAPE); null otherwise. */
70
+ periodicity: "monthly" | "quarterly" | "annual" | null;
67
71
  observationStale: boolean;
68
72
  }
69
73
 
@@ -137,6 +141,7 @@ export function projectView(
137
141
  span: points[0] ? historySpan(points[0].date, visible.filter(isUsableRatio), RANGE_WINDOWS_MS[range]) : null,
138
142
  historyStart: points[0]?.date ?? null,
139
143
  asOf: current.date,
144
+ periodicity: periodStartPeriodicity(current.date, periodsPerYear(history.slice(-24).map((point) => ({ date: point.date, value: point.ratio })))),
140
145
  observationStale: build.sourceStale === true || nowMs - parseDateMs(current.date) > indicator.staleAfterMs,
141
146
  };
142
147
  }
@@ -11,7 +11,7 @@ const columns: HeadlessPaneColumn[] = [
11
11
  export const membersHeadless: HeadlessPaneDefinition<"rows"> = {
12
12
  shape: "rows", argument: { kind: "ticker", optional: true, placeholder: "fund", description: "Covered fund or index alias; omit for the fund list." },
13
13
  options: [{ key: "tab", type: "enum", values: [{ value: "members" }, { value: "movers" }, { value: "changes" }], defaultValue: "members", description: "Members, movers or changes." }],
14
- discovery: { aliases: ["MEMB", "MRR", "IMOV"], limitations: ["ETF holdings, with file dates.", "Partial delayed member return coverage.", "Nasdaq-100 is not covered."] },
14
+ discovery: { aliases: ["MEMB", "MRR", "IMOV"], limitations: ["ETF holdings, with file dates.", "Member prices are real-time with Pro and fifteen minutes delayed otherwise; partial 1D coverage.", "Nasdaq-100 is not covered."] },
15
15
  describe: (args) => args.rawArgument ? `MEMB ${args.rawArgument}` : "Index and ETF members",
16
16
  async load(args, context) {
17
17
  const input = args.symbols[0] ?? args.rawArgument ?? "";
@@ -25,15 +25,16 @@ export const membersHeadless: HeadlessPaneDefinition<"rows"> = {
25
25
  const data = await fetchMembers(fund, context.apiClient);
26
26
  const movers = args.options.tab === "movers";
27
27
  const rows = memberRows(data.members, movers ? "movers" : "members", "", DEFAULT_SORT).flatMap((row) => row.kind === "item" ? [{ ...row.item }] : []);
28
- // Member prices are the pane's 15-minute delayed quotes. As in the pane, the fund's snapshot says
29
- // whether it is stale; the members' own flags are not what the pane reads.
30
- return { freshness: { status: data.stale ? "stale" : "delayed", delayMinutes: 15, ignoreStaleFlags: true }, rows, columns: movers ? [...columns.slice(0, 3), { key: "contribution", header: "Contrib. pp", align: "right", format: (value) => percent(value as number | null, "", 3) }] : columns,
28
+ // Member prices are the pane's quotes: real-time for a Pro account, 15 minutes delayed otherwise. As in the
29
+ // pane, the fund's snapshot says whether it is stale; the members' own flags are not what the pane reads.
30
+ const live = data.access === "realtime";
31
+ return { freshness: { status: data.stale ? "stale" : live ? "live" : "delayed", delayMinutes: 15, ignoreStaleFlags: true }, rows, columns: movers ? [...columns.slice(0, 3), { key: "contribution", header: "Contrib. pp", align: "right", format: (value) => percent(value as number | null, "", 3) }] : columns,
31
32
  complete: !data.stale && data.aggregate.fresh1D === data.aggregate.total,
32
33
  unavailableSymbols: data.members.flatMap((row) => row.symbol && row.changePercent === null ? [row.symbol] : []),
33
34
  metadata: { fund: data.fund, asOf: data.asOf, snapshotAsOf: data.snapshotAsOf, aggregate: data.aggregate, stale: data.stale, notices: [
34
35
  holdingsSourceText(input, data),
35
36
  // The pane's coverage figure, and once what the table's dashes mean instead of leaving them bare.
36
- [coverageText(data.aggregate), data.aggregate.fresh1D < data.aggregate.total ? "1D -- means no fresh delayed quote; those holdings are not counted" : ""].filter(Boolean).join(" | "),
37
+ [coverageText(data.aggregate), data.aggregate.fresh1D < data.aggregate.total ? `1D -- means no fresh ${live ? "" : "delayed "}quote; those holdings are not counted` : ""].filter(Boolean).join(" | "),
37
38
  ...holdingsCaveats(data, movers),
38
39
  ] } };
39
40
  },
@@ -17,6 +17,8 @@ import { canonicalFund, changeColumns, changeLabel, changeReason, coverageText,
17
17
 
18
18
  type ViewProps = Pick<PaneProps, "width" | "height" | "focused"> & { fund: string; active: boolean };
19
19
  const rowKey = (row: SectionedRow<FundMember>) => row.key;
20
+ /** How often live members are worth checking again: the server renews their prices every 15 seconds. */
21
+ const LIVE_MEMBERS_REFRESH_MS = 15_000;
20
22
 
21
23
  function Holdings({ fund, tab, width, height, focused, active }: ViewProps & { tab: MembersTab }) {
22
24
  const colors = useThemeColors();
@@ -39,10 +41,13 @@ function Holdings({ fund, tab, width, height, focused, active }: ViewProps & { t
39
41
  members: rows.flatMap((row) => isSectionedItemRow(row) && row.item.symbol ? [{ symbol: row.item.symbol, name: row.item.name }] : []) };
40
42
  }, [data, fund, query, rows, tab]);
41
43
  useMembersMenu("members:members-menu", memberList);
42
- useAutoRefresh(resource.updatedAt, () => { if (active) void resource.load(); });
44
+ // A Pro account's members are priced from the server's live read, renewed every 15 seconds.
45
+ const live = data?.access === "realtime";
46
+ useAutoRefresh(resource.updatedAt, () => { if (active) void resource.load(live); }, { intervalMs: live ? LIVE_MEMBERS_REFRESH_MS : null });
43
47
  usePaneRefreshKey(() => void resource.reload(), { focused, enabled: active && !search.active });
44
48
  const info = useMemo<PaneFooterSegment[]>(() => {
45
49
  if (!data) return [];
50
+ const feed = data.access === "realtime" ? "live" : "15m delayed";
46
51
  const dates = [...new Set(data.members.flatMap((row) => row.changePercent !== null && row.dailyAsOf ? [row.dailyAsOf.slice(0, 10)] : []))].sort();
47
52
  const date = dates.length === 1 ? dates[0] : dates.length ? `${dates[0]} to ${dates.at(-1)}` : data.fundDailyAsOf?.slice(0, 10);
48
53
  const partial = data.aggregate.fresh1D < data.aggregate.total;
@@ -50,10 +55,12 @@ function Holdings({ fund, tab, width, height, focused, active }: ViewProps & { t
50
55
  { id: "coverage", parts: [{ text: coverageText(data.aggregate, width < 60), tone: partial ? "warning" : "muted" }] },
51
56
  // A capture's status line says the quotes' date and delay too; it does not say returns are unavailable.
52
57
  ...(data.quotesUnavailable
53
- ? [{ id: "quote-date", title: `${date ?? "Quote date unavailable"} · 15m delayed · holdings ${data.asOf}`, parts: [{ text: "returns unavailable", tone: "muted" as const }] }]
58
+ ? [{ id: "quote-date", title: `${date ?? "Quote date unavailable"} · ${feed} · holdings ${data.asOf}`, parts: [{ text: "returns unavailable", tone: "muted" as const }] }]
54
59
  : [
55
- delayedFooterSegment({ id: "quote-delay", detail: "15m delayed", delay: "15m", quoteStatus: true }),
56
- ...(date ? [{ id: "quote-date", title: `${date} · 15m delayed · holdings ${data.asOf}`, quoteStatus: true,
60
+ data.access === "realtime"
61
+ ? { id: "quote-live", quoteStatus: true, parts: [{ text: "live", tone: "positive" as const }] }
62
+ : delayedFooterSegment({ id: "quote-delay", detail: "15m delayed", delay: "15m", quoteStatus: true }),
63
+ ...(date ? [{ id: "quote-date", title: `${date} · ${feed} · holdings ${data.asOf}`, quoteStatus: true,
57
64
  parts: [{ text: width < 60 && dates.length === 1 ? date.slice(5) : date, tone: "muted" as const }] }] : []),
58
65
  ]),
59
66
  ...(width >= 60 ? [{ id: "holdings-date", asOf: true, parts: [{ text: `holdings ${data.asOf}`, tone: "muted" as const }] }] : []),
@@ -58,6 +58,7 @@ function validDeal(deal: MnaDeal): boolean {
58
58
  && !!terms && CONSIDERATIONS.has(terms.consideration)
59
59
  && numberOrNull(terms.cashPerShare) && numberOrNull(terms.exchangeRatio)
60
60
  && textOrNull(terms.ratioSymbol) && textOrNull(terms.currency)
61
+ && (terms.election === undefined || typeof terms.election === "boolean")
61
62
  && typeof terms.cvr === "boolean" && typeof terms.partial === "boolean"
62
63
  && numberOrNull(deal.value) && textOrNull(deal.valueCurrency) && numberOrNull(deal.valueUsd)
63
64
  && day(deal.announced)