gloomberb 0.18.2 → 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 (954) 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/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -2,6 +2,8 @@ import { useCallback, useEffect, useMemo, useRef } from "react";
2
2
  import { DataTableView, EmptyState, PaneStatusBody, QueryBar, StatGrid, statGridRows, usePaneFooter, usePaneNoticeFooter,
3
3
  usePaneTicker, type DataTableCell, type DataTableColumn, type StatItem } from "../../../components";
4
4
  import { usePaneRefreshKey } from "../../../components/data-table/table-pane";
5
+ import { tableColumnWidth } from "../../../components/ui/table-layout";
6
+ import { displayWidth } from "../../../utils/format";
5
7
  import { instrumentFromTicker } from "../../../market-data/request-types";
6
8
  import { usePaneSettingValue, usePluginPaneState } from "../../../public/react";
7
9
  import { useAsyncResource } from "../../../react/async-resource";
@@ -10,11 +12,13 @@ import { useThemeColors } from "../../../theme/theme-context";
10
12
  import type { PaneProps } from "../../../types/plugin";
11
13
  import { Box } from "../../../ui";
12
14
  import { loadMacroDayEarnings, loadMacroDayHistory, loadMacroReleases, macroDayEarningsNotice } from "./client";
13
- import { macroDayEventLabel, projectMacroDays, type MacroDayEvent, type MacroDayModel } from "./model";
14
- import { MACRO_EVENT_KINDS, MACRO_EVENT_LABELS, staleMacroReleasesNotice, type MacroEventKind } from "./releases";
15
+ import { macroDayEventLabel, macroDayStats, matchesSurprise, projectMacroDays, type MacroDayEvent, type MacroDayModel } from "./model";
16
+ import { MACRO_EVENT_KINDS, MACRO_EVENT_LABELS, MACRO_SURPRISE_LABELS, MACRO_SURPRISES, staleMacroReleasesNotice, type MacroEventKind,
17
+ type MacroSurprise } from "./releases";
15
18
 
16
19
  export const LOOKBACK_OPTIONS = [{ value: "1", label: "1Y" }, { value: "2", label: "2Y" }, { value: "3", label: "3Y" }, { value: "5", label: "5Y" }];
17
20
  const RELEASE_OPTIONS = [{ value: "all", label: "All" }, ...MACRO_EVENT_KINDS.map((kind) => ({ value: kind, label: MACRO_EVENT_LABELS[kind] }))];
21
+ const SURPRISE_OPTIONS = [{ value: "all", label: "All" }, ...MACRO_SURPRISES.map((surprise) => ({ value: surprise, label: MACRO_SURPRISE_LABELS[surprise] }))];
18
22
 
19
23
  function pct(value: number | null | undefined, signed = true): string {
20
24
  if (value == null) return "--";
@@ -29,21 +33,45 @@ const MOVE: DataTableColumn[] = [
29
33
  { id: "move", label: "Move", width: 9, align: "right" },
30
34
  { id: "multiple", label: "vs Normal", width: 10, align: "right" },
31
35
  ];
36
+ /** What each release came out with, under the labels the economic calendar gives them. */
37
+ const FIGURES = [["actual", "Actual"], ["forecast", "Forecast"], ["prior", "Prior"]] as const;
38
+
39
+ /** The figure columns, shown once any listed day has figures, each as wide as its header and its widest value. */
40
+ function figureColumns(rows: readonly MacroDayEvent[]): DataTableColumn[] {
41
+ if (!rows.some((event) => event.figures)) return [];
42
+ return FIGURES.map(([id, label]) => ({ id, label, align: "right", width: tableColumnWidth({ label,
43
+ width: Math.max(6, ...rows.map((event) => displayWidth(event.figures?.[id] ?? ""))) }) }));
44
+ }
32
45
 
33
46
  /**
34
47
  * With every release listed, the release's name, widened to take the earnings marker where a row has one. With one
35
48
  * selected, a column only for the marker: every row would repeat the name.
36
49
  */
37
- function columnsFor(release: string, rows: readonly MacroDayEvent[]): DataTableColumn[] {
50
+ export function columnsFor(release: string, rows: readonly MacroDayEvent[]): DataTableColumn[] {
38
51
  const marked = rows.some((event) => event.earnings);
39
- if (release === "all") return [DATE, { id: "release", label: "Release", width: marked ? 15 : 8, align: "left" }, ...MOVE];
40
- return marked ? [DATE, { id: "release", label: "Note", width: EARNINGS_MARK.length, align: "left" }, ...MOVE] : [DATE, ...MOVE];
52
+ const values = [...figureColumns(rows), ...MOVE];
53
+ if (release === "all") return [DATE, { id: "release", label: "Release", width: marked ? 15 : 8, align: "left" }, ...values];
54
+ return marked ? [DATE, { id: "release", label: "Note", width: EARNINGS_MARK.length, align: "left" }, ...values] : [DATE, ...values];
55
+ }
56
+
57
+ const tone = (value: number | null) => value == null ? undefined : value >= 0 ? "positive" as const : "negative" as const;
58
+
59
+ /** The figures over the days a surprise filter keeps: the same four as one release's. */
60
+ function surpriseFigures(model: MacroDayModel, rows: readonly MacroDayEvent[]): StatItem[] {
61
+ const stats = macroDayStats(rows, model.normal.meanAbs);
62
+ return [
63
+ { id: "abs", label: "Avg |move|", value: pct(stats.meanAbs, false), detail: stats.count ? `${times(stats.multiple)} normal` : undefined },
64
+ { id: "mean", label: "Avg move", value: pct(stats.mean), tone: tone(stats.mean) },
65
+ { id: "up", label: "Up", value: stats.hitRate == null ? "--" : `${Math.round(stats.hitRate * 100)}%`,
66
+ detail: stats.count ? `${Math.round(stats.hitRate! * stats.count)} of ${stats.count}` : undefined },
67
+ { id: "normal", label: "Normal day", value: pct(model.normal.meanAbs, false), detail: "avg |move|" },
68
+ ];
41
69
  }
42
70
 
43
71
  function figures(model: MacroDayModel, release: string): StatItem[] {
44
72
  const normal: StatItem = { id: "normal", label: "Normal day", value: pct(model.normal.meanAbs, false), detail: "avg |move|" };
45
73
  if (release === "all") {
46
- return [...MACRO_EVENT_KINDS.map((kind): StatItem => {
74
+ return [...model.kinds.map((kind): StatItem => {
47
75
  const stats = model.byKind[kind];
48
76
  return { id: kind, label: `${MACRO_EVENT_LABELS[kind]} day`, value: pct(stats.meanAbs, false),
49
77
  detail: stats.count ? `${times(stats.multiple)} normal` : undefined };
@@ -51,7 +79,6 @@ function figures(model: MacroDayModel, release: string): StatItem[] {
51
79
  detail: `${times(model.earnings.multiple)} normal` }] : []), normal];
52
80
  }
53
81
  const stats = model.byKind[release as MacroEventKind];
54
- const tone = (value: number | null) => value == null ? undefined : value >= 0 ? "positive" as const : "negative" as const;
55
82
  return [
56
83
  { id: "abs", label: "Avg |move|", value: pct(stats.meanAbs, false), detail: stats.count ? `${times(stats.multiple)} normal` : undefined },
57
84
  { id: "mean", label: "Avg move", value: pct(stats.mean), tone: tone(stats.mean) },
@@ -66,6 +93,7 @@ export function MacroDayPane({ width, height, focused }: PaneProps) {
66
93
  const { symbol, ticker, error: identityError } = usePaneTicker();
67
94
  const [lookback, setLookback] = usePaneSettingValue("lookbackYears", "5");
68
95
  const [release, setRelease] = usePluginPaneState("release", "all");
96
+ const [surprise, setSurprise] = usePluginPaneState<MacroSurprise | "all">("surprise", "all");
69
97
  const [selectedRow, setSelectedRow] = usePluginPaneState<string | null>("selectedRow", null);
70
98
  const instrument = instrumentFromTicker(ticker, symbol);
71
99
  const instrumentKey = JSON.stringify(instrument);
@@ -88,8 +116,10 @@ export function MacroDayPane({ width, height, focused }: PaneProps) {
88
116
  [history.data, lookback, symbol]);
89
117
  const releasesNotice = history.data ? staleMacroReleasesNotice(history.data.releases) : null;
90
118
  const earningsNotice = history.data ? macroDayEarningsNotice(history.data.earnings) : null;
91
- const rows = useMemo(() => model ? model.events.filter((event) => release === "all" || event.kind === release) : [], [model, release]);
92
- const stats = useMemo(() => model?.events.length ? figures(model, release) : [], [model, release]);
119
+ const rows = useMemo(() => model ? model.events.filter((event) => (release === "all" || event.kind === release)
120
+ && matchesSurprise(event, surprise)) : [], [model, release, surprise]);
121
+ const stats = useMemo(() => !model?.events.length ? [] : surprise === "all" ? figures(model, release) : surpriseFigures(model, rows),
122
+ [model, release, surprise, rows]);
93
123
  const columns = useMemo(() => columnsFor(release, rows), [release, rows]);
94
124
 
95
125
  usePaneNoticeFooter({ registrationId: "macro-day-notices", focused,
@@ -103,6 +133,11 @@ export function MacroDayPane({ width, height, focused }: PaneProps) {
103
133
  const renderCell = useCallback((event: MacroDayEvent, column: DataTableColumn): DataTableCell => {
104
134
  if (column.id === "date") return { text: event.session === event.date ? event.date : `${event.date} → ${event.session.slice(5)}`, value: event.date };
105
135
  if (column.id === "release") return { text: release === "all" ? macroDayEventLabel(event) : event.earnings ? EARNINGS_MARK : "" };
136
+ // The print colored against the consensus, as the economic calendar colors it.
137
+ if (column.id === "actual") return { text: event.figures?.actual ?? "", color: event.figures?.surprise === "hot" ? colors.positive
138
+ : event.figures?.surprise === "cool" ? colors.negative : undefined };
139
+ if (column.id === "forecast") return { text: event.figures?.forecast ?? "" };
140
+ if (column.id === "prior") return { text: event.figures?.prior ?? "" };
106
141
  if (column.id === "move") return { text: pct(event.move), value: event.move * 100,
107
142
  color: event.move > 0 ? colors.positive : event.move < 0 ? colors.negative : undefined };
108
143
  return { text: times(event.multiple), value: event.multiple };
@@ -114,6 +149,7 @@ export function MacroDayPane({ width, height, focused }: PaneProps) {
114
149
  return <Box width={width} height={height} flexDirection="column" overflow="hidden">
115
150
  <QueryBar width={width} filters={[
116
151
  { id: "release", label: "Release", value: release, options: RELEASE_OPTIONS, onChange: setRelease, inline: true },
152
+ { id: "surprise", label: "Surprise", value: surprise, options: SURPRISE_OPTIONS, onChange: (value) => setSurprise(value as MacroSurprise | "all") },
117
153
  { id: "lookback", label: "Lookback", value: String(lookback), options: LOOKBACK_OPTIONS, onChange: setLookback },
118
154
  ]} />
119
155
  {!symbol ? <EmptyState title="Select a ticker." /> : <PaneStatusBody subject="macro-day moves" loading={history.loading && !model}
@@ -121,7 +157,7 @@ export function MacroDayPane({ width, height, focused }: PaneProps) {
121
157
  {model ? <>
122
158
  <StatGrid items={stats} width={width} />
123
159
  <DataTableView<MacroDayEvent> focused={focused} columns={columns} items={rows} rootWidth={width} rootHeight={contentHeight}
124
- getItemKey={key} emptyStateTitle="No release days." sortColumnId={null} sortDirection="desc" selectedTextOverridesCellColor
160
+ getItemKey={key} emptyStateTitle={surprise === "all" ? "No release days." : `No ${MACRO_SURPRISE_LABELS[surprise].toLowerCase()} prints.`} sortColumnId={null} sortDirection="desc" selectedTextOverridesCellColor
125
161
  selection={{ kind: "id", selectedId: selectedRow, getId: key, onChange: (id) => setSelectedRow(id) }}
126
162
  getExportMetadata={() => [["symbol", model.symbol], ["from", model.start ?? ""], ["to", model.asOf ?? ""],
127
163
  ["units", "percent, close to close on the release day"]]}
@@ -1,27 +1,47 @@
1
- // Published US release days, not a rule engine: the dates each release came
1
+ // Published release days, not a rule engine: the dates each release came
2
2
  // out, read from the publishers' own archives. A release cancelled or moved (the
3
3
  // 2025 shutdown) is as published, and a scheduled date is not a release day
4
- // until it is out. Dates are New York calendar days.
4
+ // until it is out. Dates are New York calendar days. Brazil's IPCA days come
5
+ // from Gloom Cloud only; the list the app ships with has the US releases.
5
6
  import { zonedDateKey } from "../../../utils/zoned-date-time";
6
7
  import { MACRO_RELEASE_TABLE } from "./release-table";
7
8
 
8
- export type MacroEventKind = "cpi" | "jobs" | "fomc";
9
+ /** The US releases the bundled list carries, and the ones HIVG reads around. */
10
+ export type UsMacroEventKind = "cpi" | "jobs" | "fomc";
11
+ export type MacroEventKind = UsMacroEventKind | "ipca";
9
12
 
10
- export const MACRO_EVENT_KINDS: readonly MacroEventKind[] = ["cpi", "jobs", "fomc"];
13
+ export const US_MACRO_EVENT_KINDS: readonly UsMacroEventKind[] = ["cpi", "jobs", "fomc"];
14
+ export const MACRO_EVENT_KINDS: readonly MacroEventKind[] = [...US_MACRO_EVENT_KINDS, "ipca"];
11
15
 
12
- export const MACRO_EVENT_LABELS: Record<MacroEventKind, string> = { cpi: "CPI", jobs: "Jobs", fomc: "FOMC" };
16
+ export const MACRO_EVENT_LABELS: Record<MacroEventKind, string> = { cpi: "CPI", jobs: "Jobs", fomc: "FOMC", ipca: "IPCA" };
13
17
 
14
- /** BLS news release archives for CPI and the Employment Situation, and the Federal Reserve's meeting calendar. */
18
+ /** BLS news release archives for CPI and the Employment Situation, the Federal Reserve's meeting calendar, IBGE's calendar. */
15
19
  export const MACRO_RELEASE_SOURCES: Record<MacroEventKind, string> = {
16
20
  cpi: "https://www.bls.gov/bls/news-release/cpi.htm",
17
21
  jobs: "https://www.bls.gov/bls/news-release/empsit.htm",
18
22
  fomc: "https://www.federalreserve.gov/monetarypolicy/fomccalendars.htm",
23
+ ipca: "https://www.ibge.gov.br/calendario-indicadores-novoportal.html",
19
24
  };
20
25
 
21
26
  /** A list more than this many days behind today says so: a release day may be missing from its end. */
22
27
  export const MACRO_RELEASES_STALE_DAYS = 14;
23
28
 
24
- export interface MacroRelease { kind: MacroEventKind; date: string }
29
+ /** Above the consensus (hot), below it (cool), at it (in-line). */
30
+ export type MacroSurprise = "hot" | "cool" | "in-line";
31
+ export const MACRO_SURPRISES: readonly MacroSurprise[] = ["hot", "cool", "in-line"];
32
+ export const MACRO_SURPRISE_LABELS: Record<MacroSurprise, string> = { hot: "Hot", cool: "Cool", "in-line": "In line" };
33
+
34
+ /** What a release day came out with: the headline, its print, the consensus before it and the figure before that. */
35
+ export interface MacroReleaseFigures {
36
+ /** The headline the figures are for: "Inflation Rate YoY", "IPCA m/m". */
37
+ event: string;
38
+ actual: string | null;
39
+ forecast: string | null;
40
+ prior: string | null;
41
+ surprise: MacroSurprise | null;
42
+ }
43
+
44
+ export interface MacroRelease { kind: MacroEventKind; date: string; figures?: MacroReleaseFigures }
25
45
 
26
46
  export interface MacroReleaseList {
27
47
  /** Oldest first. */
@@ -37,29 +57,51 @@ const byDate = (left: MacroRelease, right: MacroRelease) => left.date.localeComp
37
57
 
38
58
  /** The list the app ships with: the floor whenever the server's list is missing or older. */
39
59
  export function bundledMacroReleases(): MacroReleaseList {
40
- const releases = MACRO_EVENT_KINDS.flatMap((kind) => Object.entries(MACRO_RELEASE_TABLE.days[kind]).flatMap(([year, days]) =>
60
+ const releases = US_MACRO_EVENT_KINDS.flatMap((kind) => Object.entries(MACRO_RELEASE_TABLE.days[kind]).flatMap(([year, days]) =>
41
61
  days.map((day) => ({ kind, date: `${year}-${day}` }))));
42
62
  return { releases: releases.sort(byDate), coveredThrough: MACRO_RELEASE_TABLE.coveredThrough };
43
63
  }
44
64
 
65
+ const text = (value: unknown) => typeof value === "string" && value.trim() ? value.trim() : null;
66
+
67
+ /** A day's figures as served, or undefined when they break the contract. */
68
+ function servedFigures(value: unknown): MacroReleaseFigures | undefined {
69
+ const figures = value as Partial<Record<keyof MacroReleaseFigures, unknown>> | null;
70
+ const event = text(figures?.event);
71
+ if (!event) return undefined;
72
+ const surprise = MACRO_SURPRISES.find((candidate) => candidate === figures?.surprise) ?? null;
73
+ return { event, actual: text(figures?.actual), forecast: text(figures?.forecast), prior: text(figures?.prior), surprise };
74
+ }
75
+
45
76
  /**
46
77
  * The served list extends the floor past its end; the floor keeps its own
47
- * days up to there. A served list that breaks the contract, or ends no later
48
- * than the floor, adds nothing.
78
+ * days up to there. IPCA, which the floor does not carry, is the served list's
79
+ * through its end, and left out when the server lists none. Every day takes
80
+ * the figures the server has for it. A served list that breaks the contract,
81
+ * or ends no later than the floor, adds nothing.
49
82
  */
50
83
  export function mergeMacroReleases(floor: MacroReleaseList, served: unknown): MacroReleaseList {
51
- const payload = served as { coveredThrough?: unknown; releases?: Partial<Record<MacroEventKind, unknown>> } | null;
84
+ const payload = served as { coveredThrough?: unknown; releases?: Partial<Record<MacroEventKind, unknown>>;
85
+ figures?: Partial<Record<MacroEventKind, Record<string, unknown>>> } | null;
52
86
  const coveredThrough = payload?.coveredThrough;
53
87
  if (!isDate(coveredThrough) || coveredThrough <= floor.coveredThrough) return floor;
54
88
  const later: MacroRelease[] = [];
55
- for (const kind of MACRO_EVENT_KINDS) {
89
+ for (const kind of US_MACRO_EVENT_KINDS) {
56
90
  const dates = payload?.releases?.[kind];
57
91
  if (!Array.isArray(dates) || !dates.every(isDate)) return floor;
58
92
  for (const date of new Set(dates)) {
59
93
  if (date > floor.coveredThrough && date <= coveredThrough) later.push({ kind, date });
60
94
  }
61
95
  }
62
- return { releases: [...floor.releases, ...later].sort(byDate), coveredThrough };
96
+ const ipca = payload?.releases?.ipca;
97
+ if (Array.isArray(ipca) && ipca.every(isDate)) {
98
+ for (const date of new Set(ipca)) if (date <= coveredThrough) later.push({ kind: "ipca", date });
99
+ }
100
+ const figuresOf = (release: MacroRelease): MacroRelease => {
101
+ const figures = servedFigures(payload?.figures?.[release.kind]?.[release.date]);
102
+ return figures ? { ...release, figures } : release;
103
+ };
104
+ return { releases: [...floor.releases, ...later].map(figuresOf).sort(byDate), coveredThrough };
63
105
  }
64
106
 
65
107
  /** Whole days from the list's last covered day to today in New York. */
@@ -31,7 +31,14 @@ export interface MarketHeatmapBoard extends MarketHeatmapResult {
31
31
  const DEFAULT_COUNT = 80;
32
32
  /** The most names one board asks for; a server that serves fewer answers with its own maximum. */
33
33
  const MAX_MARKET_HEATMAP_COUNT = 500;
34
- const CACHE_TTL_MS = 60_000;
34
+ /**
35
+ * How often a board is worth checking again: a real-time board's live read
36
+ * is renewed every 15 seconds on the server, a delayed board's snapshot is
37
+ * cached there for a minute.
38
+ */
39
+ export function heatmapCheckIntervalMs(board: Pick<MarketHeatmapResult, "access"> | null | undefined): number {
40
+ return board?.access === "realtime" ? 15_000 : 60_000;
41
+ }
35
42
  const activeFetches = new Map<string, Promise<MarketHeatmapBoard>>();
36
43
  const memoryCache = new Map<string, { expiresAt: number; result: MarketHeatmapBoard }>();
37
44
 
@@ -90,7 +97,7 @@ export async function fetchMarketHeatmap(
90
97
  const fetchPromise = loadMarketHeatmap(universe, count, sources)
91
98
  .then((result) => {
92
99
  if (useCache) {
93
- memoryCache.set(cacheKey, { result, expiresAt: Date.now() + CACHE_TTL_MS });
100
+ memoryCache.set(cacheKey, { result, expiresAt: Date.now() + heatmapCheckIntervalMs(result) });
94
101
  }
95
102
  return result;
96
103
  })
@@ -1,5 +1,5 @@
1
1
  /**
2
- * What `gloomberb shot HM` certifies: the tab the heat map drew, what its tiles
2
+ * What `gloom shot HM` certifies: the tab the heat map drew, what its tiles
3
3
  * are sized by, how many tiles and sectors are plotted, and whether its
4
4
  * snapshot had loaded. The heat map has
5
5
  * no table rows or labeled values, so this is how a capture counts as data.
@@ -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 });
@@ -5,6 +5,7 @@ import type {
5
5
  CloudSessionMoversSide,
6
6
  } from "../../../api-client/market-movers";
7
7
  import type { DataProvider } from "../../../types/data-provider";
8
+ import { logFailure } from "../../../utils/log-failure";
8
9
  import {
9
10
  CATEGORY_MAP,
10
11
  moverRegularSession,
@@ -17,7 +18,8 @@ import {
17
18
  } from "./model";
18
19
  import {
19
20
  fetchPreferredMarketMovers,
20
- fetchTrending,
21
+ fetchTrendingResult,
22
+ type CachedResult,
21
23
  type MarketMoversResult,
22
24
  type PreferredMoversOptions,
23
25
  type TrendingSymbol,
@@ -29,6 +31,8 @@ export interface MarketMoverTabResult extends MarketMoversResult {
29
31
  quotes: MoverQuote[];
30
32
  /** What the list is ranked by; absent for trending, which keeps its source's order. */
31
33
  rankedBy?: MoverRanking;
34
+ /** Requested trending names whose quotes did not load. */
35
+ unavailableSymbols?: string[];
32
36
  }
33
37
 
34
38
  /** Rows a list shows. */
@@ -45,42 +49,52 @@ export interface MarketMoverTabDependencies {
45
49
  count: number,
46
50
  options?: PreferredMoversOptions,
47
51
  ): Promise<MarketMoversResult>;
48
- fetchTrending(count: number, options?: { forceRefresh?: boolean }): Promise<TrendingSymbol[]>;
52
+ fetchTrending(count: number, options?: { forceRefresh?: boolean }): Promise<CachedResult<TrendingSymbol[]>>;
49
53
  }
50
54
 
51
55
  const defaultDependencies: MarketMoverTabDependencies = {
52
56
  fetchPreferred: (category, count, options) => fetchPreferredMarketMovers(category, count, options),
53
- fetchTrending: (count, options) => fetchTrending(count, undefined, options),
57
+ fetchTrending: (count, options) => fetchTrendingResult(count, undefined, options),
54
58
  };
55
59
 
56
60
  async function hydrateTrending(
57
61
  trending: readonly TrendingSymbol[],
58
62
  provider: DataProvider | null,
59
- ): Promise<MoverQuote[]> {
60
- 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);
61
65
  const bySymbol = new Map<string, MoverQuote>();
62
- if (!provider) return [];
63
- if (provider.getQuotesBatch) {
64
- const results = await provider.getQuotesBatch(
65
- symbols.map((symbol) => ({ symbol, exchange: "" })),
66
- ).catch(() => []);
67
- for (const result of results) {
68
- 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);
69
75
  }
70
- } else {
76
+ } else if (provider) {
71
77
  await Promise.all(symbols.map(async (symbol) => {
72
78
  try {
73
79
  const quote = await provider.getQuote(symbol, "");
74
80
  bySymbol.set(symbol, screenerQuoteFromQuote(symbol, quote));
75
- } catch {
76
- // Missing quotes are omitted from a ranked list.
81
+ } catch (error) {
82
+ logFailure("market-movers", "Trending quote failed")(error);
77
83
  }
78
84
  }));
79
85
  }
80
- return symbols.flatMap((symbol) => {
81
- const quote = bySymbol.get(symbol);
82
- return quote ? [quote] : [];
83
- });
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;
84
98
  }
85
99
 
86
100
  export async function loadMarketMoverTab(
@@ -92,11 +106,12 @@ export async function loadMarketMoverTab(
92
106
  const { basis, ...fetchOptions } = options ?? {};
93
107
  if (tab === "trending") {
94
108
  const trending = await dependencies.fetchTrending(LIST_ROWS, fetchOptions);
109
+ const hydrated = await hydrateTrending(trending.data, provider);
95
110
  return {
96
111
  tab,
97
- quotes: await hydrateTrending(trending, provider),
112
+ ...hydrated,
98
113
  source: "gloom",
99
- stale: false,
114
+ stale: trending.stale || !!hydrated.unavailableSymbols?.length,
100
115
  };
101
116
  }
102
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 ? (