gloomberb 0.18.4 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (600) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/package.json +1 -1
  4. package/patches/electrobun@1.18.1.patch +169 -5
  5. package/src/account/auth-model.ts +7 -3
  6. package/src/api-client/auth.ts +9 -4
  7. package/src/api-client/catalysts.ts +2 -1
  8. package/src/api-client/cot.ts +6 -2
  9. package/src/api-client/credit-documents.ts +6 -0
  10. package/src/api-client/data.ts +31 -6
  11. package/src/api-client/equity-screener.ts +24 -0
  12. package/src/api-client/fund-facts.ts +45 -4
  13. package/src/api-client/index.ts +171 -11
  14. package/src/api-client/live-scan.ts +91 -0
  15. package/src/api-client/market-discovery.ts +10 -0
  16. package/src/api-client/market-movers.ts +7 -0
  17. package/src/api-client/members.ts +13 -1
  18. package/src/api-client/perps.ts +43 -0
  19. package/src/api-client/request.ts +222 -41
  20. package/src/api-client/research-activity.ts +6 -12
  21. package/src/api-client/types.ts +74 -0
  22. package/src/app/keybindings/index.ts +3 -0
  23. package/src/app/keybindings/labels.ts +18 -1
  24. package/src/app/keybindings/resolve.ts +14 -0
  25. package/src/app/pane-runtime/plugin-bindings.ts +9 -5
  26. package/src/app/runtime/broker-import.ts +42 -27
  27. package/src/app/runtime/plugin-bindings.ts +73 -56
  28. package/src/architecture/core-builtin-allowlist.json +1 -1
  29. package/src/architecture/pane-tabs-allowlist.json +3 -0
  30. package/src/architecture/ttl-caches-allowlist.json +19 -0
  31. package/src/brokers/sync-broker-instance.ts +2 -8
  32. package/src/capabilities/chart-series.ts +1 -1
  33. package/src/cli/commands/crypto-hints.ts +40 -24
  34. package/src/cli/commands/fred-series.ts +5 -0
  35. package/src/cli/commands/keybindings.ts +23 -0
  36. package/src/cli/commands/market.ts +138 -46
  37. package/src/cli/commands/options-chain.ts +107 -10
  38. package/src/cli/commands/options-leaps.ts +9 -3
  39. package/src/cli/commands/overview.ts +176 -39
  40. package/src/cli/commands/search.ts +39 -3
  41. package/src/cli/commands/themes.ts +11 -2
  42. package/src/cli/commands/ticker.ts +57 -35
  43. package/src/cli/company-name-hint.ts +41 -0
  44. package/src/cli/earnings-calendar.ts +1 -1
  45. package/src/cli/errors.ts +10 -2
  46. package/src/cli/export-source.ts +29 -1
  47. package/src/cli/glossary.ts +73 -1
  48. package/src/cli/history-rows.ts +87 -16
  49. package/src/cli/index.ts +2 -0
  50. package/src/cli/known-gaps.ts +5 -2
  51. package/src/cli/listing-arg.ts +195 -56
  52. package/src/cli/output-file.ts +68 -0
  53. package/src/cli/pane-functions/capabilities.ts +3 -0
  54. package/src/cli/pane-functions/catalog.ts +80 -7
  55. package/src/cli/pane-functions/dom.ts +13 -3
  56. package/src/cli/pane-functions/freshness.ts +111 -16
  57. package/src/cli/pane-functions/function-help.ts +23 -13
  58. package/src/cli/pane-functions/headless.ts +56 -12
  59. package/src/cli/pane-functions/index.ts +58 -16
  60. package/src/cli/pane-functions/market-session.ts +81 -9
  61. package/src/cli/pane-functions/options.ts +19 -1
  62. package/src/cli/pane-functions/report.ts +5 -1
  63. package/src/cli/pane-functions/resolver.ts +35 -8
  64. package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
  65. package/src/cli/pane-functions/screenshot-types.ts +5 -0
  66. package/src/cli/quote-answer.ts +30 -13
  67. package/src/cli/report-tables.ts +18 -7
  68. package/src/cli/restore-plugins.ts +13 -1
  69. package/src/cli/result.ts +57 -5
  70. package/src/cli/ticker-resolution.ts +3 -2
  71. package/src/components/chart/composite/composite-chart.tsx +26 -4
  72. package/src/components/chart/composite/format.ts +27 -0
  73. package/src/components/chart/composite/interactions.ts +6 -0
  74. package/src/components/chart/composite/legend.tsx +45 -7
  75. package/src/components/chart/composite/levels.ts +2 -0
  76. package/src/components/chart/composite/panel-gestures.ts +33 -0
  77. package/src/components/chart/composite/panel-series.ts +1 -0
  78. package/src/components/chart/composite/panel-surface.tsx +61 -5
  79. package/src/components/chart/composite/range-statistics.ts +62 -0
  80. package/src/components/chart/composite/rasterizer.ts +24 -13
  81. package/src/components/chart/composite/scene.ts +46 -7
  82. package/src/components/chart/composite/series-axis-tags.tsx +16 -9
  83. package/src/components/chart/composite/series-cues.ts +14 -0
  84. package/src/components/chart/composite/text-renderer.ts +9 -2
  85. package/src/components/chart/composite/tool-catalog.ts +36 -0
  86. package/src/components/chart/composite/tools.ts +203 -44
  87. package/src/components/chart/composite/types.ts +4 -0
  88. package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
  89. package/src/components/command-bar/assist/inventory.ts +2 -1
  90. package/src/components/command-bar/commands/direct/index.ts +28 -13
  91. package/src/components/command-bar/pane-templates/items.ts +3 -2
  92. package/src/components/command-bar/panel/prompt-binding.ts +0 -8
  93. package/src/components/command-bar/workflow/alert.ts +1 -1
  94. package/src/components/command-bar/workflow/collection-actions.ts +3 -3
  95. package/src/components/layout/header.tsx +26 -40
  96. package/src/components/layout/pane/footer/index.tsx +1 -0
  97. package/src/components/layout/pane/footer/model.ts +27 -0
  98. package/src/components/onboarding/onboarding-frame.tsx +1 -1
  99. package/src/components/onboarding/onboarding-wizard.tsx +4 -1
  100. package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -9
  101. package/src/components/onboarding/wizard-broker-sync.ts +0 -1
  102. package/src/components/onboarding/wizard-positions.ts +3 -3
  103. package/src/components/ticker/list-table-view.tsx +4 -1
  104. package/src/components/ui/choice-dialog.tsx +23 -18
  105. package/src/components/ui/choice-groups.ts +18 -0
  106. package/src/components/ui/data-table/opentui/index.tsx +9 -7
  107. package/src/components/ui/data-table/opentui/model.ts +26 -1
  108. package/src/components/ui/data-table/types.ts +2 -0
  109. package/src/components/ui/display.tsx +5 -1
  110. package/src/components/ui/list-view.tsx +8 -4
  111. package/src/components/ui/query-bar-keys.tsx +2 -0
  112. package/src/components/ui/query-bar.tsx +1 -0
  113. package/src/components/ui/select-button.tsx +5 -1
  114. package/src/components/ui/select-field.tsx +1 -0
  115. package/src/components/ui/table-layout.ts +8 -5
  116. package/src/core/app-runtime.ts +2 -0
  117. package/src/core/app-services.ts +2 -2
  118. package/src/core/state/app/layout.ts +2 -0
  119. package/src/core/state/app/state.ts +9 -0
  120. package/src/core/state/app/types.ts +3 -0
  121. package/src/data/config/chart-settings.ts +1 -1
  122. package/src/data/json-ticker-repository.ts +17 -8
  123. package/src/data/saved-copies.ts +55 -16
  124. package/src/data/ticker-repository.ts +16 -9
  125. package/src/data/ticker-writes.ts +81 -0
  126. package/src/data/ttl-cache.ts +165 -0
  127. package/src/docs/snapshot.json +427 -216
  128. package/src/i18n/es.ts +19 -3
  129. package/src/i18n/ja.ts +19 -3
  130. package/src/i18n/ko.ts +19 -3
  131. package/src/i18n/zh-cn.ts +19 -3
  132. package/src/i18n/zh-tw.ts +19 -3
  133. package/src/market-data/coordinator/financials.ts +10 -2
  134. package/src/market-data/coordinator/index.ts +3 -1
  135. package/src/market-data/coordinator/quotes.ts +4 -2
  136. package/src/market-data/depositary-pair.ts +2 -2
  137. package/src/market-data/fund-facts.ts +50 -0
  138. package/src/market-data/market/change-basis.ts +48 -7
  139. package/src/market-data/market/dated-previous-close.ts +203 -0
  140. package/src/market-data/market/format.ts +25 -0
  141. package/src/market-data/market/freshness.ts +2 -1
  142. package/src/market-data/market/futures-week.ts +68 -0
  143. package/src/market-data/market/status.ts +16 -4
  144. package/src/market-data/options-alternatives.ts +141 -4
  145. package/src/market-data/quotes/contributions.ts +20 -2
  146. package/src/market-data/quotes/resolution.ts +3 -0
  147. package/src/market-data/selectors.ts +3 -0
  148. package/src/news/aggregator.ts +113 -9
  149. package/src/news/cloud-session.ts +21 -0
  150. package/src/news/hooks.ts +1 -0
  151. package/src/news/news-model.ts +1 -0
  152. package/src/news/types.ts +11 -0
  153. package/src/notifications/notification-log.ts +6 -4
  154. package/src/plugins/builtin/alerts/alert-engine.ts +25 -2
  155. package/src/plugins/builtin/alerts/alert-log.ts +33 -0
  156. package/src/plugins/builtin/alerts/calendar-events.ts +57 -6
  157. package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
  158. package/src/plugins/builtin/alerts/cli.ts +380 -82
  159. package/src/plugins/builtin/alerts/command.ts +31 -0
  160. package/src/plugins/builtin/alerts/constants.ts +1 -1
  161. package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
  162. package/src/plugins/builtin/alerts/fired-log.ts +113 -8
  163. package/src/plugins/builtin/alerts/format.ts +80 -4
  164. package/src/plugins/builtin/alerts/headless.ts +30 -7
  165. package/src/plugins/builtin/alerts/history-rows.ts +7 -3
  166. package/src/plugins/builtin/alerts/history.ts +2 -0
  167. package/src/plugins/builtin/alerts/index.tsx +135 -22
  168. package/src/plugins/builtin/alerts/live.ts +3 -3
  169. package/src/plugins/builtin/alerts/metric-command.ts +134 -0
  170. package/src/plugins/builtin/alerts/metric-data.ts +111 -0
  171. package/src/plugins/builtin/alerts/metric-model.ts +324 -0
  172. package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
  173. package/src/plugins/builtin/alerts/pane.tsx +90 -39
  174. package/src/plugins/builtin/alerts/quotes.ts +6 -0
  175. package/src/plugins/builtin/alerts/storage.ts +37 -10
  176. package/src/plugins/builtin/alerts/types.ts +7 -0
  177. package/src/plugins/builtin/analytics/index.tsx +2 -1
  178. package/src/plugins/builtin/analytics/risk-client.ts +16 -5
  179. package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
  180. package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
  181. package/src/plugins/builtin/analytics/risk-model.ts +55 -9
  182. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
  183. package/src/plugins/builtin/attention/index.tsx +2 -1
  184. package/src/plugins/builtin/attention/listing.ts +14 -0
  185. package/src/plugins/builtin/backtest/headless.ts +10 -5
  186. package/src/plugins/builtin/backtest/pane.tsx +9 -4
  187. package/src/plugins/builtin/backtest/presets.ts +29 -3
  188. package/src/plugins/builtin/broker-manager/index.tsx +10 -5
  189. package/src/plugins/builtin/broker-manager/model.ts +6 -1
  190. package/src/plugins/builtin/broker-trading/controller.ts +22 -12
  191. package/src/plugins/builtin/broker-trading/index.tsx +13 -1
  192. package/src/plugins/builtin/broker-trading/order-feed.ts +9 -4
  193. package/src/plugins/builtin/broker-trading/pane.tsx +1 -1
  194. package/src/plugins/builtin/buildout/cells.tsx +12 -4
  195. package/src/plugins/builtin/buildout/format.ts +38 -0
  196. package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
  197. package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
  198. package/src/plugins/builtin/buildout/table-model.ts +23 -2
  199. package/src/plugins/builtin/builtin-plugin-meta.ts +7 -3
  200. package/src/plugins/builtin/catalysts/model.ts +2 -1
  201. package/src/plugins/builtin/changelog/index.tsx +9 -6
  202. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +6 -1
  203. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +1 -1
  204. package/src/plugins/builtin/chart-composer/cli-options.ts +9 -5
  205. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +12 -2
  206. package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -2
  207. package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
  208. package/src/plugins/builtin/chart-composer/editor.tsx +7 -5
  209. package/src/plugins/builtin/chart-composer/formula.ts +71 -18
  210. package/src/plugins/builtin/chart-composer/headless-schema.ts +21 -4
  211. package/src/plugins/builtin/chart-composer/headless.ts +19 -3
  212. package/src/plugins/builtin/chart-composer/index.tsx +1 -1
  213. package/src/plugins/builtin/chart-composer/pane.tsx +53 -9
  214. package/src/plugins/builtin/chart-composer/presets.ts +50 -15
  215. package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
  216. package/src/plugins/builtin/chart-composer/session-history.ts +18 -9
  217. package/src/plugins/builtin/chart-composer/settings.ts +27 -0
  218. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +40 -26
  219. package/src/plugins/builtin/chat/content/command-suggestions.ts +93 -0
  220. package/src/plugins/builtin/chat/content/composer.tsx +13 -6
  221. package/src/plugins/builtin/chat/content/footer.tsx +6 -3
  222. package/src/plugins/builtin/chat/content/index.tsx +50 -21
  223. package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
  224. package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
  225. package/src/plugins/builtin/chat/index.tsx +23 -0
  226. package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
  227. package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
  228. package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
  229. package/src/plugins/builtin/chat/pane-links/commands.ts +271 -0
  230. package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
  231. package/src/plugins/builtin/chat/pane-links/open.ts +8 -1
  232. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
  233. package/src/plugins/builtin/clinical-trials/model.ts +0 -9
  234. package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
  235. package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
  236. package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
  237. package/src/plugins/builtin/cloud/plugin.tsx +1 -1
  238. package/src/plugins/builtin/company-attention/building.tsx +5 -1
  239. package/src/plugins/builtin/company-attention/client.ts +8 -9
  240. package/src/plugins/builtin/company-attention/evidence.ts +4 -1
  241. package/src/plugins/builtin/company-attention/moves.tsx +5 -1
  242. package/src/plugins/builtin/company-attention/pane.tsx +9 -2
  243. package/src/plugins/builtin/company-attention/signals.tsx +5 -1
  244. package/src/plugins/builtin/correlation/headless.ts +13 -5
  245. package/src/plugins/builtin/correlation/history.ts +22 -0
  246. package/src/plugins/builtin/cot/client.ts +22 -18
  247. package/src/plugins/builtin/cot/headless.ts +15 -10
  248. package/src/plugins/builtin/cot/model.ts +14 -1
  249. package/src/plugins/builtin/cot/pane.tsx +22 -14
  250. package/src/plugins/builtin/credit-boards/client.ts +6 -10
  251. package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
  252. package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
  253. package/src/plugins/builtin/credit-conditions/model.ts +4 -0
  254. package/src/plugins/builtin/credit-conditions/series.ts +3 -1
  255. package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
  256. package/src/plugins/builtin/credit-documents/export.ts +173 -0
  257. package/src/plugins/builtin/credit-documents/headless.ts +7 -7
  258. package/src/plugins/builtin/credit-documents/model.ts +104 -14
  259. package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
  260. package/src/plugins/builtin/custom-view/sources.ts +2 -0
  261. package/src/plugins/builtin/dividend-yield/client.ts +131 -23
  262. package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
  263. package/src/plugins/builtin/dividend-yield/model.ts +8 -5
  264. package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
  265. package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
  266. package/src/plugins/builtin/dividend-yield/types.ts +20 -2
  267. package/src/plugins/builtin/dividend-yield/view.ts +30 -2
  268. package/src/plugins/builtin/docs/targets.ts +5 -1
  269. package/src/plugins/builtin/earnings/board-model.ts +16 -15
  270. package/src/plugins/builtin/earnings/board.tsx +62 -71
  271. package/src/plugins/builtin/earnings/headless.ts +40 -4
  272. package/src/plugins/builtin/earnings/scope.ts +31 -43
  273. package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
  274. package/src/plugins/builtin/earnings-calls/format.ts +31 -2
  275. package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
  276. package/src/plugins/builtin/earnings-calls/model.ts +6 -1
  277. package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
  278. package/src/plugins/builtin/econ/calendar-model.ts +14 -9
  279. package/src/plugins/builtin/econ/figures.ts +72 -0
  280. package/src/plugins/builtin/econ/index.tsx +33 -3
  281. package/src/plugins/builtin/econ/types.ts +4 -0
  282. package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
  283. package/src/plugins/builtin/econ-statistics/headless.ts +85 -35
  284. package/src/plugins/builtin/econ-statistics/stats.ts +37 -9
  285. package/src/plugins/builtin/econ-statistics/view.ts +3 -0
  286. package/src/plugins/builtin/equity-screener/categories.ts +179 -0
  287. package/src/plugins/builtin/equity-screener/client.ts +4 -2
  288. package/src/plugins/builtin/equity-screener/headless.ts +144 -13
  289. package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
  290. package/src/plugins/builtin/equity-screener/model.ts +99 -10
  291. package/src/plugins/builtin/equity-screener/pane.tsx +70 -15
  292. package/src/plugins/builtin/exposure/charts.tsx +2 -2
  293. package/src/plugins/builtin/exposure/model.ts +13 -1
  294. package/src/plugins/builtin/exposure/pane.tsx +4 -4
  295. package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
  296. package/src/plugins/builtin/futures/index.tsx +1 -0
  297. package/src/plugins/builtin/futures/model.ts +2 -1
  298. package/src/plugins/builtin/futures/table.tsx +2 -2
  299. package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
  300. package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
  301. package/src/plugins/builtin/fx-matrix/client.ts +11 -3
  302. package/src/plugins/builtin/fx-matrix/headless.ts +6 -3
  303. package/src/plugins/builtin/fx-matrix/index.tsx +16 -4
  304. package/src/plugins/builtin/fx-matrix/live-legs.ts +54 -3
  305. package/src/plugins/builtin/gpu/headless.ts +8 -2
  306. package/src/plugins/builtin/help/function-index.ts +4 -1
  307. package/src/plugins/builtin/help/index.tsx +1 -0
  308. package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
  309. package/src/plugins/builtin/help/shortcut-model.ts +1 -1
  310. package/src/plugins/builtin/holders/fund-holders.ts +51 -0
  311. package/src/plugins/builtin/holders/headless.ts +18 -1
  312. package/src/plugins/builtin/iv-history/client.ts +52 -11
  313. package/src/plugins/builtin/iv-history/format.ts +36 -23
  314. package/src/plugins/builtin/iv-history/headless.ts +36 -18
  315. package/src/plugins/builtin/iv-history/index.tsx +2 -2
  316. package/src/plugins/builtin/iv-history/model.ts +163 -27
  317. package/src/plugins/builtin/iv-history/pane.tsx +10 -6
  318. package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
  319. package/src/plugins/builtin/iv-history/universe.ts +5 -1
  320. package/src/plugins/builtin/jobs/client.ts +25 -29
  321. package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
  322. package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
  323. package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
  324. package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
  325. package/src/plugins/builtin/macro-day/pane.tsx +7 -5
  326. package/src/plugins/builtin/macro-day/release-table.ts +2 -2
  327. package/src/plugins/builtin/market-heatmap/data.ts +8 -33
  328. package/src/plugins/builtin/market-movers/client.ts +25 -7
  329. package/src/plugins/builtin/market-movers/footer.ts +2 -2
  330. package/src/plugins/builtin/market-movers/headless.ts +32 -12
  331. package/src/plugins/builtin/market-movers/index.tsx +26 -14
  332. package/src/plugins/builtin/market-movers/min-float.ts +74 -0
  333. package/src/plugins/builtin/market-movers/model.ts +4 -1
  334. package/src/plugins/builtin/market-movers/screener.ts +14 -0
  335. package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
  336. package/src/plugins/builtin/market-movers/session-table.ts +4 -3
  337. package/src/plugins/builtin/market-movers/table.ts +17 -5
  338. package/src/plugins/builtin/members/breadth-pane.tsx +82 -0
  339. package/src/plugins/builtin/members/client.ts +19 -4
  340. package/src/plugins/builtin/members/headless.ts +20 -7
  341. package/src/plugins/builtin/members/index.tsx +9 -9
  342. package/src/plugins/builtin/members/model.ts +23 -4
  343. package/src/plugins/builtin/members/pane.tsx +25 -15
  344. package/src/plugins/builtin/news/index.tsx +1 -0
  345. package/src/plugins/builtin/news/wire/categories.ts +19 -3
  346. package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
  347. package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
  348. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
  349. package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
  350. package/src/plugins/builtin/openfda/client.ts +14 -2
  351. package/src/plugins/builtin/openfda/index.tsx +3 -2
  352. package/src/plugins/builtin/openfda/model.ts +9 -0
  353. package/src/plugins/builtin/openfda/pane.tsx +42 -6
  354. package/src/plugins/builtin/options/analytics.ts +54 -6
  355. package/src/plugins/builtin/options/enrichment.ts +17 -5
  356. package/src/plugins/builtin/options/model-spot.ts +5 -2
  357. package/src/plugins/builtin/options/strike-window.ts +2 -1
  358. package/src/plugins/builtin/options/table.ts +6 -9
  359. package/src/plugins/builtin/options/types.ts +2 -0
  360. package/src/plugins/builtin/options/view.tsx +42 -12
  361. package/src/plugins/builtin/options-positioning/client.ts +30 -0
  362. package/src/plugins/builtin/options-positioning/headless.ts +74 -21
  363. package/src/plugins/builtin/options-positioning/index.tsx +4 -4
  364. package/src/plugins/builtin/options-positioning/model.ts +122 -14
  365. package/src/plugins/builtin/options-positioning/pane.tsx +87 -42
  366. package/src/plugins/builtin/options-scenario/client.ts +116 -47
  367. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
  368. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
  369. package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
  370. package/src/plugins/builtin/options-scenario/csp.ts +8 -2
  371. package/src/plugins/builtin/options-scenario/index.tsx +9 -7
  372. package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
  373. package/src/plugins/builtin/pe-band/model.ts +12 -49
  374. package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
  375. package/src/plugins/builtin/perps/cascade.ts +236 -0
  376. package/src/plugins/builtin/perps/client.ts +56 -2
  377. package/src/plugins/builtin/perps/freshness.ts +12 -10
  378. package/src/plugins/builtin/perps/headless.ts +65 -9
  379. package/src/plugins/builtin/perps/index.tsx +7 -5
  380. package/src/plugins/builtin/perps/live-rows.ts +10 -3
  381. package/src/plugins/builtin/perps/model.ts +18 -4
  382. package/src/plugins/builtin/perps/pane.tsx +32 -31
  383. package/src/plugins/builtin/perps/status-line.ts +25 -0
  384. package/src/plugins/builtin/plugin-module.ts +5 -1
  385. package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
  386. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
  387. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
  388. package/src/plugins/builtin/portfolio-list/cli/render.ts +12 -7
  389. package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
  390. package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
  391. package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
  392. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
  393. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
  394. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +3 -1
  395. package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
  396. package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
  397. package/src/plugins/builtin/primary-dealers/client.ts +13 -38
  398. package/src/plugins/builtin/rate-path/pane.tsx +2 -2
  399. package/src/plugins/builtin/realized-vol/index.tsx +2 -2
  400. package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
  401. package/src/plugins/builtin/relative-rotation/client.ts +18 -4
  402. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  403. package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
  404. package/src/plugins/builtin/relative-rotation/model.ts +16 -40
  405. package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
  406. package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
  407. package/src/plugins/builtin/research/event-model.ts +10 -8
  408. package/src/plugins/builtin/research/headless.ts +1 -1
  409. package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
  410. package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
  411. package/src/plugins/builtin/research/relative-valuation-pane.tsx +11 -9
  412. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
  413. package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
  414. package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
  415. package/src/plugins/builtin/scanner/feed.ts +2 -2
  416. package/src/plugins/builtin/scanner/flow-model.ts +50 -4
  417. package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
  418. package/src/plugins/builtin/scanner/flow-session.ts +146 -0
  419. package/src/plugins/builtin/scanner/headless.ts +204 -35
  420. package/src/plugins/builtin/scanner/index.ts +40 -6
  421. package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
  422. package/src/plugins/builtin/scanner/live-feed.ts +168 -0
  423. package/src/plugins/builtin/scanner/live-headless.ts +138 -0
  424. package/src/plugins/builtin/scanner/live-model.ts +362 -0
  425. package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
  426. package/src/plugins/builtin/scanner/live-track.ts +186 -0
  427. package/src/plugins/builtin/scanner/lock-note.ts +3 -2
  428. package/src/plugins/builtin/seasonality/headless.ts +10 -1
  429. package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
  430. package/src/plugins/builtin/sec/fund-facts.ts +116 -34
  431. package/src/plugins/builtin/sec/headless.ts +2 -1
  432. package/src/plugins/builtin/series-inventory.ts +3 -0
  433. package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
  434. package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
  435. package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
  436. package/src/plugins/builtin/shared/earnings-report.ts +2 -2
  437. package/src/plugins/builtin/shared/job-posting.ts +1 -0
  438. package/src/plugins/builtin/shared/macro-releases.ts +65 -0
  439. package/src/plugins/builtin/shared/members-menu.tsx +3 -2
  440. package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
  441. package/src/plugins/builtin/shared/report-freshness.ts +3 -2
  442. package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
  443. package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
  444. package/src/plugins/builtin/shared/ticker-company.ts +77 -0
  445. package/src/plugins/builtin/shared/use-quote-board.ts +10 -3
  446. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
  447. package/src/plugins/builtin/shared/volatility/pricing.ts +26 -1
  448. package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
  449. package/src/plugins/builtin/themes/headless.ts +6 -4
  450. package/src/plugins/builtin/themes/model.ts +17 -8
  451. package/src/plugins/builtin/themes/pane.tsx +7 -7
  452. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
  453. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
  454. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
  455. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
  456. package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
  457. package/src/plugins/builtin/ticker-detail/overview/model.ts +1 -1
  458. package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
  459. package/src/plugins/builtin/ticker-detail/quote-footer.ts +6 -1
  460. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
  461. package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
  462. package/src/plugins/builtin/time-sales/pane.tsx +31 -19
  463. package/src/plugins/builtin/treasury-daily/client.ts +41 -5
  464. package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
  465. package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
  466. package/src/plugins/builtin/treasury-daily/model.ts +50 -3
  467. package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
  468. package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
  469. package/src/plugins/builtin/vol-surface/client.ts +9 -17
  470. package/src/plugins/builtin/vol-surface/headless.ts +63 -14
  471. package/src/plugins/builtin/vol-surface/index.tsx +2 -2
  472. package/src/plugins/builtin/vol-surface/model.ts +22 -7
  473. package/src/plugins/builtin/vol-surface/pane.tsx +48 -9
  474. package/src/plugins/builtin/vol-surface/tables.ts +31 -3
  475. package/src/plugins/builtin/volatility/dvol.ts +46 -0
  476. package/src/plugins/builtin/volatility/index.tsx +2 -2
  477. package/src/plugins/builtin/volatility/pane.tsx +4 -4
  478. package/src/plugins/builtin/volatility/series.ts +26 -0
  479. package/src/plugins/builtin/world-indices/footer.ts +1 -1
  480. package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
  481. package/src/plugins/catalog-browser.ts +13 -8
  482. package/src/plugins/catalog-manifest.ts +2 -1
  483. package/src/plugins/marketplace/model.ts +18 -5
  484. package/src/portfolio/column-values.ts +5 -5
  485. package/src/portfolio/futures-positions.ts +6 -3
  486. package/src/portfolio/position-quantity.ts +15 -9
  487. package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
  488. package/src/remote/resources.ts +2 -1
  489. package/src/renderers/browser/app-services.ts +1 -7
  490. package/src/renderers/browser/config-host.ts +2 -55
  491. package/src/renderers/browser/main.tsx +7 -57
  492. package/src/renderers/dom/data-table/row.tsx +26 -0
  493. package/src/renderers/dom/desktop/list-view.tsx +13 -10
  494. package/src/renderers/dom/desktop/query-bar.tsx +4 -2
  495. package/src/renderers/dom/desktop/select-field.tsx +4 -2
  496. package/src/renderers/dom/host/chart-surface.tsx +21 -0
  497. package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
  498. package/src/renderers/electrobun/bun/desktop/backend.ts +29 -7
  499. package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
  500. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
  501. package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
  502. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
  503. package/src/renderers/electrobun/bun/desktop/update.ts +173 -5
  504. package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
  505. package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
  506. package/src/renderers/electrobun/bun/index.ts +25 -1
  507. package/src/renderers/electrobun/shared/app-name.ts +30 -0
  508. package/src/renderers/electrobun/shared/protocol.ts +10 -0
  509. package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
  510. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  511. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
  512. package/src/renderers/electrobun/view/main.tsx +24 -1
  513. package/src/renderers/electrobun/view/news-source.ts +3 -1
  514. package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
  515. package/src/renderers/electrobun/view/view-ids.ts +85 -0
  516. package/src/renderers/opentui/start.tsx +5 -0
  517. package/src/renderers/opentui/toast-host.tsx +71 -43
  518. package/src/series/registry.ts +1 -0
  519. package/src/series/types.ts +6 -0
  520. package/src/series/validate.ts +1 -0
  521. package/src/sources/gloomberb-cloud/index.ts +1 -0
  522. package/src/sources/gloomberb-cloud/news.ts +47 -7
  523. package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
  524. package/src/sources/provider-router/batches.ts +10 -2
  525. package/src/sources/provider-router/financial-routes.ts +3 -3
  526. package/src/sources/provider-router/financials.ts +15 -3
  527. package/src/sources/provider-router/history.ts +28 -7
  528. package/src/sources/provider-router/index.ts +149 -10
  529. package/src/sources/provider-router/search.ts +13 -2
  530. package/src/state/app/context/index.tsx +3 -0
  531. package/src/state/ticker-cleanup.ts +50 -0
  532. package/src/sync/auth-transition.ts +19 -9
  533. package/src/sync/baseline.ts +10 -4
  534. package/src/sync/controller.ts +70 -19
  535. package/src/sync/core-contributors.ts +90 -31
  536. package/src/sync/react.ts +4 -1
  537. package/src/sync/types.ts +3 -0
  538. package/src/telemetry/stall-reports-dom.ts +38 -0
  539. package/src/telemetry/stall-reports-node.ts +75 -0
  540. package/src/telemetry/stall-reports.ts +214 -0
  541. package/src/telemetry/usage-counts.ts +0 -18
  542. package/src/test-support/preload.ts +14 -0
  543. package/src/theme/colors.ts +8 -0
  544. package/src/theme/themes.ts +10 -0
  545. package/src/tickers/company-name.ts +103 -3
  546. package/src/tickers/listing-venues.ts +38 -3
  547. package/src/tickers/search/bare-symbol.ts +36 -0
  548. package/src/tickers/search/index.ts +36 -7
  549. package/src/tickers/search/ranking.ts +10 -1
  550. package/src/tickers/search/types.ts +5 -0
  551. package/src/tickers/terminal-codes.ts +19 -0
  552. package/src/time-series/alignment.ts +1 -1
  553. package/src/time-series/base-series.ts +13 -5
  554. package/src/time-series/daily-valuation.ts +62 -0
  555. package/src/time-series/economic.ts +18 -4
  556. package/src/time-series/field-catalog.ts +2 -4
  557. package/src/time-series/filed-trailing-eps.ts +197 -0
  558. package/src/time-series/forward-valuation.ts +32 -0
  559. package/src/time-series/fundamentals.ts +198 -7
  560. package/src/time-series/hooks.ts +1 -0
  561. package/src/time-series/ice-credit.ts +3 -0
  562. package/src/time-series/price-comparison.ts +30 -2
  563. package/src/time-series/price-units.ts +72 -2
  564. package/src/time-series/resolve-context.ts +7 -1
  565. package/src/time-series/resolve.ts +116 -15
  566. package/src/time-series/series-presentation.ts +40 -6
  567. package/src/time-series/session-bar.ts +11 -0
  568. package/src/time-series/spec.ts +5 -3
  569. package/src/time-series/studies.ts +278 -74
  570. package/src/time-series/total-return.ts +160 -0
  571. package/src/time-series/transforms.ts +3 -3
  572. package/src/time-series/types.ts +27 -1
  573. package/src/time-series/valuation-releases.ts +39 -0
  574. package/src/types/data-provider.ts +9 -1
  575. package/src/types/desktop-window.ts +2 -0
  576. package/src/types/financials.ts +73 -2
  577. package/src/types/headless.ts +61 -5
  578. package/src/types/instrument.ts +3 -0
  579. package/src/types/news-source.ts +1 -0
  580. package/src/types/plugin.ts +10 -1
  581. package/src/ui/host.tsx +3 -0
  582. package/src/updater/command-names.ts +12 -7
  583. package/src/updater/failure.ts +4 -1
  584. package/src/utils/cli-output.ts +42 -1
  585. package/src/utils/crypto-pair.ts +44 -0
  586. package/src/utils/financial-statements.ts +6 -1
  587. package/src/utils/forward-dividend.ts +2 -0
  588. package/src/utils/fundamentals.ts +24 -3
  589. package/src/utils/fx-market-hours.ts +26 -3
  590. package/src/utils/main-thread-stall.ts +35 -2
  591. package/src/utils/market-capitalization.ts +24 -1
  592. package/src/utils/network-failure.ts +9 -6
  593. package/src/utils/option-expiry.ts +48 -1
  594. package/src/utils/options.ts +10 -0
  595. package/src/utils/plugin-proxy-hosts.json +1 -0
  596. package/src/utils/price-history.ts +12 -1
  597. package/src/utils/shell-word.ts +8 -0
  598. package/src/utils/trailing-dividend.ts +53 -4
  599. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
  600. package/src/renderers/browser/first-screen.ts +0 -193
@@ -79,6 +79,14 @@ function builtInPanePrefixes(paneId: string): string[] {
79
79
  return command ? getCommandPrefixes(command) : [];
80
80
  }
81
81
 
82
+ /**
83
+ * What a user types for a function, as the catalog lists it and every error names it: a template's
84
+ * shortcut or id, a pane opened by a built-in command (LAY) by that command's mnemonic, else the pane's id.
85
+ */
86
+ export function paneFunctionCode(template: PaneTemplateDef | undefined, pane: PaneDef): string {
87
+ return template?.shortcut?.prefix ?? template?.id ?? builtInPanePrefixes(pane.id)[0] ?? pane.id;
88
+ }
89
+
82
90
  function registerResolverToken(
83
91
  lookup: Map<string, PaneTemplateDef | PaneDef>,
84
92
  token: string | undefined,
@@ -195,7 +203,8 @@ export function nearFunctionCodes(
195
203
  const near = new Map<PaneTemplateDef, string>();
196
204
  for (const template of registry.paneTemplates.values()) {
197
205
  const prefix = template.shortcut?.prefix;
198
- if (!prefix) continue;
206
+ // An unlisted function is never offered for a typo.
207
+ if (!prefix || template.listed === false) continue;
199
208
  const code = [prefix, ...template.shortcut?.aliases ?? []].find((candidate) => {
200
209
  const known = normalizeLookupToken(candidate);
201
210
  return (!commandWord || known[0] === wanted[0]) && typoDistance(wanted, known) === 1;
@@ -215,6 +224,7 @@ export function suggestedFunctionCodes(registry: PaneFunctionCatalog, name: stri
215
224
  const wanted = normalizeLookupToken(name);
216
225
  if (!wanted) return [];
217
226
  return [...registry.paneTemplates.values()].flatMap((template) => {
227
+ if (template.listed === false) return [];
218
228
  const pane = registry.panes.get(template.paneId);
219
229
  const words = pane ? getHeadlessPaneDefinition(template, pane)?.discovery?.suggestFor ?? [] : [];
220
230
  const code = template.shortcut?.prefix;
@@ -277,9 +287,15 @@ async function buildTemplateCatalogEntry(
277
287
  };
278
288
  }
279
289
 
290
+ /**
291
+ * The functions `gloom catalog` and search list. An unlisted one (`listed:
292
+ * false`) is left out, and its pane is not listed in its place; `unlisted`
293
+ * keeps it, for its own help (`fn ATTN --help`).
294
+ */
280
295
  export async function buildPaneCatalogEntries(
281
296
  registry: PaneFunctionCatalog,
282
297
  context: MarketContext,
298
+ { unlisted = false }: { unlisted?: boolean } = {},
283
299
  ): Promise<PaneCatalogEntry[]> {
284
300
  const entries: PaneCatalogEntry[] = [];
285
301
  const templatedPaneIds = new Set<string>();
@@ -288,6 +304,7 @@ export async function buildPaneCatalogEntries(
288
304
  const pane = registry.panes.get(template.paneId);
289
305
  if (!pane) continue;
290
306
  templatedPaneIds.add(pane.id);
307
+ if (template.listed === false && !unlisted) continue;
291
308
  entries.push(await buildTemplateCatalogEntry(template, pane, context));
292
309
  }
293
310
 
@@ -296,7 +313,7 @@ export async function buildPaneCatalogEntries(
296
313
  const [shortcut, ...aliases] = builtInPanePrefixes(pane.id);
297
314
  const argument = paneFunctionArgument(undefined, pane);
298
315
  entries.push({
299
- token: shortcut ?? pane.id,
316
+ token: paneFunctionCode(undefined, pane),
300
317
  label: pane.name,
301
318
  description: `Open the ${pane.name} pane.`,
302
319
  paneId: pane.id,
@@ -333,6 +350,14 @@ const ALL_WORDS_WITH_FLAGS_BAND = 1000;
333
350
  const PER_MATCHED_WORD = 100;
334
351
  /** Loose matches (no function carries every word) listed before the rest are left to a refined query. */
335
352
  const LOOSE_MATCH_LIMIT = 5;
353
+ /** Loose matches a word of the query names (in the function's code, name or aliases) are all listed, up to this many. */
354
+ const LOOSE_NAMED_LIMIT = 8;
355
+ /** A query word found in what the function is called (its code, name or aliases) outweighs one found in its keywords or description. */
356
+ const PER_WORD_IN_NAME = 3;
357
+ /** A query word that begins a function's code (`vol` for VOLS, `fx` for FXC) is the start of typing it. */
358
+ const PER_WORD_STARTING_CODE = 3;
359
+ /** A query word that is one of the function's own keywords (`vol` for the volatility functions, which also say volume's) names it. */
360
+ const PER_WORD_IS_KEYWORD = 3;
336
361
 
337
362
  function phraseBand(entry: PaneCatalogEntry, phrase: string): number {
338
363
  const lower = (values: Array<string | undefined>) => values
@@ -375,6 +400,12 @@ function nameAndDescription(entry: PaneCatalogEntry): string {
375
400
  return nameAndDescriptionFields(entry).join(" ");
376
401
  }
377
402
 
403
+ /** What a function is called: its code, name and aliases, apart from the keywords and description that say what it covers. */
404
+ function identityFields(entry: PaneCatalogEntry): string[] {
405
+ return [entry.token, entry.label, entry.paneName, entry.shortcut, ...entry.aliases]
406
+ .filter((value): value is string => !!value).map((value) => value.toLowerCase().replace(/\s+/g, " "));
407
+ }
408
+
378
409
  function flagText(entry: PaneCatalogEntry): string {
379
410
  return [
380
411
  entry.argKind,
@@ -394,12 +425,14 @@ interface CatalogMatchScore {
394
425
  terms: number;
395
426
  /** Those found in the function's name, keywords or description. */
396
427
  named: number;
428
+ /** Those found in what the function is called: its code, name or aliases. */
429
+ called: number;
397
430
  }
398
431
 
399
432
  function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogMatchScore {
400
433
  const terms = queryTerms(query);
401
- if (terms.length === 0) return { score: 1, terms: 0, named: 0 };
402
- const none = { score: 0, terms: terms.length, named: 0 };
434
+ if (terms.length === 0) return { score: 1, terms: 0, named: 0, called: 0 };
435
+ const none = { score: 0, terms: terms.length, named: 0, called: 0 };
403
436
 
404
437
  const exactTokens = [
405
438
  entry.token,
@@ -414,6 +447,8 @@ function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogM
414
447
  const named = nameAndDescription(entry);
415
448
  const flags = flagText(entry);
416
449
  const wholeQuery = query.toLowerCase().trim().replace(/\s+/g, " ");
450
+ const called = identityFields(entry);
451
+ const codes = [entry.token, entry.shortcut, ...entry.aliases].filter((value): value is string => !!value).map((value) => normalizeLookupToken(value));
417
452
 
418
453
  let score = containsPhrase(`${named} ${flags}`, wholeQuery) ? 12 : 0;
419
454
  // A query that is one of the function's own keywords ("hedge" for OSA) beats one found inside a
@@ -423,9 +458,16 @@ function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogM
423
458
  if (keywords.includes(wholeQuery)) score += 4;
424
459
  let matchedTerms = 0;
425
460
  let matchedNamed = 0;
461
+ let matchedCalled = 0;
426
462
  let matchedFlagKeys = 0;
427
463
  for (const term of terms) {
428
464
  const normalized = normalizeLookupToken(term);
465
+ if (called.some((field) => containsPhrase(field, term))) {
466
+ score += PER_WORD_IN_NAME;
467
+ matchedCalled += 1;
468
+ }
469
+ if (codes.some((code) => normalized.length >= 2 && code.startsWith(normalized))) score += PER_WORD_STARTING_CODE;
470
+ if (keywords.includes(term)) score += PER_WORD_IS_KEYWORD;
429
471
  // A term starts a word: "rate" is found in "rates" but not in "separate", nor "budget" in "budgetBps".
430
472
  if (exactTokens.includes(normalized)) {
431
473
  score += 8;
@@ -455,12 +497,13 @@ function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogM
455
497
  score += Math.round((matchedTerms / terms.length) * 8);
456
498
  if (entry.capability.botSafe) score += 2;
457
499
  // One word has no phrase to prefer: it keeps the plain term scores.
458
- if (terms.length === 1) return { score, terms: 1, named: matchedNamed };
500
+ if (terms.length === 1) return { score, terms: 1, named: matchedNamed, called: matchedCalled };
459
501
  const allWords = matchedNamed === terms.length ? ALL_WORDS_BAND : matchedTerms === terms.length ? ALL_WORDS_WITH_FLAGS_BAND : 0;
460
502
  return {
461
503
  score: score + matchedTerms * PER_MATCHED_WORD + (phraseBand(entry, wholeQuery) || allWords),
462
504
  terms: terms.length,
463
505
  named: matchedNamed,
506
+ called: matchedCalled,
464
507
  };
465
508
  }
466
509
 
@@ -535,8 +578,14 @@ export function selectPaneCatalogMatches(ranked: PaneCatalogEntry[], query: stri
535
578
  const shown = every(complete).slice(0, limit);
536
579
  return { shown, hidden: ranked.length - shown.length, loose: false };
537
580
  }
581
+ // No function carries every word: the ones a word names come first, the code or name of a function being what a
582
+ // reader types ("fx vol" is FXC, whose name has fx, and VOLS, whose name has vol), ahead of one that mentions a word
583
+ // in its keywords ("implied fx" in ADR) or its flags, and however many of the words a weaker match has.
538
584
  const named = scored.filter(({ named }) => named > 0);
539
- const shown = every(named.length > 0 ? named : scored).slice(0, Math.min(limit, LOOSE_MATCH_LIMIT));
585
+ const pool = named.length > 0 ? named : scored;
586
+ const leading = pool.filter((item) => item.called > 0).slice(0, LOOSE_NAMED_LIMIT);
587
+ const rest = pool.filter((item) => !leading.includes(item)).slice(0, Math.max(0, LOOSE_MATCH_LIMIT - leading.length));
588
+ const shown = every([...leading, ...rest]).slice(0, limit);
540
589
  return { shown, hidden: ranked.length - shown.length, loose: true };
541
590
  }
542
591
 
@@ -576,7 +625,7 @@ function optionDescription(option: PaneFunctionOptionDef): string {
576
625
  const choices = optionChoices(option);
577
626
  const parts = [option.description.replace(/\.$/, "")];
578
627
  // An enum that also reads other values (a bar size of any length) lists its values as examples.
579
- if (choices.join("|").length > MAX_INLINE_CHOICES) parts.push(`${option.normalize ? "Such as" : "One of"} ${choices.join(", ")}`);
628
+ if (choices.join("|").length > MAX_INLINE_CHOICES) parts.push(`${option.list ? "Each one of" : option.normalize ? "Such as" : "One of"} ${choices.join(", ")}`);
580
629
  if (option.defaultValue !== undefined && option.defaultValue !== "") parts.push(`Default ${String(option.defaultValue)}`);
581
630
  return `${parts.join(". ")}.`;
582
631
  }
@@ -587,6 +636,26 @@ export function limitationSentence(text: string): string {
587
636
  return !trimmed || /[.!?]["')\]]*$/.test(trimmed) ? trimmed : `${trimmed}.`;
588
637
  }
589
638
 
639
+ /**
640
+ * Names as lines of at most `width`, each name whole and the names apart by
641
+ * semicolons, since a name may hold a comma (Furnishings, Fixtures & Appliances).
642
+ */
643
+ function packNames(names: readonly string[], width: number): string[] {
644
+ const lines: string[] = [];
645
+ let line = "";
646
+ names.forEach((name, index) => {
647
+ const word = index < names.length - 1 ? `${name};` : name;
648
+ if (line && line.length + 1 + word.length > width) {
649
+ lines.push(line);
650
+ line = word;
651
+ } else {
652
+ line = line ? `${line} ${word}` : word;
653
+ }
654
+ });
655
+ if (line) lines.push(line);
656
+ return lines;
657
+ }
658
+
590
659
  function renderCatalogEntry(entry: PaneCatalogEntry): string {
591
660
  const width = Math.min(cliTerminalWidth() ?? CATALOG_TEXT_WIDTH, CATALOG_TEXT_WIDTH);
592
661
  const capability = entry.capability;
@@ -620,6 +689,10 @@ function renderCatalogEntry(entry: PaneCatalogEntry): string {
620
689
  ));
621
690
  }
622
691
 
692
+ for (const { title, items } of capability.reference ?? []) {
693
+ lines.push("", renderSection(title), ...packNames(items, width - 2).map((line) => ` ${line}`));
694
+ }
695
+
623
696
  lines.push("", renderSection("Examples"));
624
697
  if (capability.reportReadiness !== "unsupported") {
625
698
  lines.push(...wrapCommandLine(`gloom fn ${invocation}`, width));
@@ -1,6 +1,6 @@
1
1
  import type { DesktopPaneShotRenderedRow } from "../desktop-pane-shot";
2
2
  import { cliStyles, cliTerminalWidth, renderSection, renderTable, wrapText } from "../../utils/cli-output";
3
- import { formatUtcTime } from "../../utils/utc-time";
3
+ import { formatUtcTime, parseReportTime } from "../../utils/utc-time";
4
4
  import type { MarketContext } from "../types";
5
5
  import type { PaneFunctionReport } from "./report";
6
6
  import type { ResolvedPaneFunction } from "./resolver";
@@ -83,12 +83,22 @@ function domCellKeys(row: DesktopPaneShotRenderedRow): string[] {
83
83
  });
84
84
  }
85
85
 
86
+ const DAY_MS = 86_400_000;
87
+ /** A time of day in what a cell draws: `11:27`, `9am`. */
88
+ const DRAWN_CLOCK = /\d{1,2}:\d{2}|\b\d{1,2}\s?[ap]m\b/i;
89
+
86
90
  /**
87
91
  * A pane may shorten a time to fit ("Wed 11:27", "Oct 2"); the report prints
88
- * the instant behind it with its date and zone instead.
92
+ * the instant behind it with its date and zone instead. An instant at exactly
93
+ * 00:00 UTC that the cell draws without a time of day (a filing's date, an
94
+ * all-day event) is a day, not a midnight: it prints as the date, as a
95
+ * date-only value does. The CSV and JSON keep the instant.
89
96
  */
90
97
  function cellText(cell: DesktopPaneShotRenderedRow["cells"][number]): string {
91
- return cell.instant ? formatUtcTime(cell.instant) || cell.text : cell.text;
98
+ if (!cell.instant) return cell.text;
99
+ const time = parseReportTime(cell.instant);
100
+ if (time && !time.dateOnly && time.time % DAY_MS === 0 && !DRAWN_CLOCK.test(cell.text)) return formatUtcTime({ ...time, dateOnly: true });
101
+ return formatUtcTime(cell.instant) || cell.text;
92
102
  }
93
103
 
94
104
  interface DomTable {
@@ -11,7 +11,15 @@ import type {
11
11
  import { localTimeSuffix, parseReportTime, type ReportTime } from "../../utils/utc-time";
12
12
  import { isRecord } from "../../utils/guards";
13
13
  import { latestRegularSessionClose, readIndexSession } from "../../market-data/market/freshness";
14
- import { reportMarketSession, reportVenueSessionDates, type ReportMarket, type SessionObservation, type VenueSessionDate } from "./market-session";
14
+ import {
15
+ reportMarketSession,
16
+ reportVenueMarkets,
17
+ reportVenueSessionDates,
18
+ type ReportMarket,
19
+ type SessionObservation,
20
+ type VenueMarket,
21
+ type VenueSessionDate,
22
+ } from "./market-session";
15
23
  import { savedCopyShownAt } from "../../data/saved-copies";
16
24
  import { releasedText } from "../../utils/release-date";
17
25
 
@@ -77,6 +85,13 @@ export interface ReportFreshness {
77
85
  tradingDayMarket?: string;
78
86
  /** Where the venues of a quote report stand now, from their session calendars. */
79
87
  market?: ReportMarket;
88
+ /**
89
+ * With a declared `datesEachVenue`, when the rows trade on two or three
90
+ * markets that do not all stand alike: where each stands and when it opens,
91
+ * which the status line gives in place of `market` (`LSE opens 08:00 UTC ·
92
+ * US 13:30 UTC`).
93
+ */
94
+ markets?: VenueMarket[];
80
95
  /**
81
96
  * With a declared `datesEachVenue`, when the rows trade on more than one
82
97
  * market: each market's session date, which the status line gives in place
@@ -100,8 +115,8 @@ export interface ReportFreshness {
100
115
  */
101
116
  sources?: ReportSourceAsOf[];
102
117
  /**
103
- * Whole minutes from the oldest of `sources` (or, declared `oldestAge`, the
104
- * oldest observation) to when this report was built: `oldest 9 min`.
118
+ * Whole minutes from the oldest of `sources` (or, declared `oldestAge` or
119
+ * `ageOnly`, the oldest observation) to when this report was built: `oldest 9 min`.
105
120
  */
106
121
  oldestAgeMinutes?: number;
107
122
  /** The data states no feed (`status` is `unreported`) and its line says only its time and age (`ageOnly`). */
@@ -125,16 +140,21 @@ export interface ReportFreshness {
125
140
  /**
126
141
  * Refreshing the data failed and a copy saved earlier answered: when that
127
142
  * copy was saved, an ISO instant in UTC. The status line then says
128
- * `couldn't refresh; saved 21:49 UTC` in place of how current the data is.
143
+ * `couldn't refresh; saved copy from 21:49 UTC` in place of how current the data is.
129
144
  */
130
145
  savedAt?: string;
146
+ /**
147
+ * Nothing was served: the data service could not be reached and no saved
148
+ * copy answered. The line then names no time, since nothing was retrieved.
149
+ */
150
+ unreached?: true;
131
151
  }
132
152
 
133
153
  /**
134
154
  * The freshness a command prints, saying when what it shows (`shown`: its
135
155
  * rows, or the data its line is drawn from) came from a copy saved earlier
136
156
  * because refreshing it failed (`collectSavedCopies`): its status line then
137
- * reads `couldn't refresh; saved 21:49 UTC` instead of live or delayed.
157
+ * reads `couldn't refresh; saved copy from 21:49 UTC` instead of live or delayed.
138
158
  */
139
159
  export function withSavedCopy<F extends ReportFreshness | undefined>(freshness: F, shown: unknown): F {
140
160
  if (!freshness || freshness.savedAt) return freshness;
@@ -463,9 +483,11 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
463
483
  // A bar still forming covers its period through a later day than the one it is dated by.
464
484
  const periodToDate = readPeriodToDate(declared.periodToDate, now);
465
485
  const asOf = declaredAsOf ?? periodToDate?.through ?? newest([...observations.units, ...observations.extra]);
466
- // The oldest source, not the newest, says how far behind the view can be.
467
- const agedFrom = sources.length ? oldest(sources.map(({ time }) => time))
468
- : declared.oldestAge || declared.ageOnly ? oldest(observations.units) ?? asOf : null;
486
+ // The oldest source, not the newest, says how far behind the view can be. A line that is dated by its age says how
487
+ // old its oldest observation is, even beside each source's newest: a source can stream some rows and not others.
488
+ const oldestSource = oldest(sources.map(({ time }) => time));
489
+ const agedFrom = declared.ageOnly ? oldest(observations.units) ?? oldestSource ?? asOf
490
+ : oldestSource ?? (declared.oldestAge ? oldest(observations.units) ?? asOf : null);
469
491
  const oldestAgeMinutes = agedFrom && !agedFrom.dateOnly ? Math.max(0, Math.floor((now - agedFrom.time) / 60_000)) : null;
470
492
  // A loader that dates its data itself also says how old the oldest part is, or nothing;
471
493
  // `oldest: null` says the rows are a history, whose first entry is not stale data.
@@ -527,6 +549,9 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
527
549
  }
528
550
  const { market, closeDate, closeMarket } = reportMarketSession(signals.sessions, now);
529
551
  const venueSessions = declared.datesEachVenue && !declaredAsOf ? reportVenueSessionDates(signals.sessions, now) : [];
552
+ // Each market's own state and open, when they are not all one: `LSE opens 08:00 UTC · US 13:30 UTC`.
553
+ const venueMarkets = declared.datesEachVenue ? reportVenueMarkets(signals.sessions, now) : [];
554
+ const markets = venueMarkets.length > 0 && !sameMarketText(venueMarkets, now) ? venueMarkets : [];
530
555
  // The close wording dates the newest observation, so only when that is what `asOf` is.
531
556
  const asOfClose = closeDate && asOf && !declaredAsOf ? closeDate : null;
532
557
  const tradingDayMarket = asOfClose ? closeMarket
@@ -577,6 +602,7 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
577
602
  ...(asOfClose ? { asOfClose } : {}),
578
603
  ...(tradingDayMarket ? { tradingDayMarket } : {}),
579
604
  ...(market ? { market } : {}),
605
+ ...(markets.length > 0 ? { markets } : {}),
580
606
  ...(venueSessions.length > 0 ? { venueSessions } : {}),
581
607
  ...(lagDays != null ? { lagDays } : {}),
582
608
  ...(observation ? { observation } : {}),
@@ -819,7 +845,7 @@ function onRetrievalDay(iso: string, retrievedAt: string): boolean {
819
845
 
820
846
  /**
821
847
  * What a report answered from a saved copy says in place of how current its
822
- * data is: `couldn't refresh; saved 21:49 UTC`, with the day when the copy was
848
+ * data is: `couldn't refresh; saved copy from 21:49 UTC`, with the day when the copy was
823
849
  * saved on another day than the report was built.
824
850
  */
825
851
  function savedCopyText(savedAt: string, retrievedAt: string, local: boolean): string {
@@ -827,7 +853,7 @@ function savedCopyText(savedAt: string, retrievedAt: string, local: boolean): st
827
853
  if (!Number.isFinite(at)) return "couldn't refresh";
828
854
  const iso = new Date(at).toISOString();
829
855
  const time = onRetrievalDay(iso, retrievedAt) ? `${iso.slice(11, 16)} UTC${local ? localTimeSuffix(at) : ""}` : timeText(iso, local);
830
- return `couldn't refresh; saved ${time}`;
856
+ return `couldn't refresh; saved copy from ${time}`;
831
857
  }
832
858
 
833
859
  /** `US and XETRA`, `US, XETRA and EPA`. */
@@ -850,6 +876,21 @@ function venueSessionsText(sessions: readonly VenueSessionDate[]): string {
850
876
  return groups.map(({ markets, date, close }) => `${listText(markets)} ${dayText(date)} ${close ? "close" : "session"}`).join(", ");
851
877
  }
852
878
 
879
+ /**
880
+ * An as-of the feed stamped at exactly 00:00:00.000 UTC reads as the day it
881
+ * names, as a date-only value does: a daily close, a filing's date or a
882
+ * published report's has no time of day, so `Mon 26 Oct 2026 00:00 UTC` would
883
+ * claim one. Quotes keep their time, as does anything a feed or a venue's
884
+ * sessions date, and bars of a size under a day, whose midnight bar opens then.
885
+ */
886
+ function asOfAsDay(freshness: ReportFreshness, time: ReportTime | null): ReportTime | null {
887
+ if (!time || time.dateOnly || time.time % DAY_MS !== 0) return time;
888
+ const feed = freshness.status === "live" || freshness.status === "delayed" || freshness.feed != null;
889
+ const intradayBars = freshness.basis === "intraday bars";
890
+ return feed || intradayBars || freshness.market || freshness.sources?.length || freshness.oldestAgeMinutes != null
891
+ ? time : { ...time, dateOnly: true };
892
+ }
893
+
853
894
  /**
854
895
  * The dated as-of: a session close, a UTC time, a date, or when the report was
855
896
  * retrieved; with the oldest observation unless `short`, or when the line says
@@ -861,7 +902,7 @@ function asOfText(freshness: ReportFreshness, short: boolean, local: boolean, un
861
902
  if (freshness.venueSessions?.length) return venueSessionsText(freshness.venueSessions);
862
903
  const market = freshness.tradingDayMarket;
863
904
  const period = freshness.periodicity;
864
- const time = parseReportTime(freshness.asOf);
905
+ const time = asOfAsDay(freshness, parseReportTime(freshness.asOf));
865
906
  const reference = freshness.referencePeriod;
866
907
  // `Sep 2026, released Tue 20 Oct`: the period the figure covers, then when it was released.
867
908
  const released = reference ? releasedText(freshness.asOf, reference) : null;
@@ -913,10 +954,11 @@ function reopenText(market: ReportMarket, now: number, local: boolean): { text:
913
954
 
914
955
  /**
915
956
  * `markets closed until Mon`; `short` is the compact form a narrow capture
916
- * falls back to (`reopens Mon`). A time is always the regular session's open,
917
- * and says so (`pre-market open · regular session opens 13:30 UTC`), so it is
957
+ * falls back to (`reopens Mon`). A time is the regular session's open, and
958
+ * says so (`pre-market open · regular session opens 13:30 UTC`), so it is
918
959
  * never read as when the pre-market opens, nor a US market as closed until
919
- * then while its pre-market trades first.
960
+ * then while its pre-market trades first. A futures venue's Sunday open is no
961
+ * regular session's, so it reads `markets closed · reopens 22:00 UTC`.
920
962
  */
921
963
  function marketText(market: ReportMarket, now: number, short: boolean, local: boolean): string {
922
964
  const reopen = reopenText(market, now, local);
@@ -930,6 +972,8 @@ function marketText(market: ReportMarket, now: number, short: boolean, local: bo
930
972
  return short ? `pre-market · regular opens ${reopen.text}` : `pre-market open · regular session opens ${reopen.text}`;
931
973
  case "closed":
932
974
  if (!reopen) return short ? "closed" : "markets closed";
975
+ // A futures venue's Sunday open is its first trade of the week, which no regular session is.
976
+ if (reopen.time && market.firstTrade) return short ? `reopens ${reopen.text}` : `markets closed · reopens ${reopen.text}`;
933
977
  if (reopen.time) return short ? `regular opens ${reopen.text}` : `markets closed · regular session opens ${reopen.text}`;
934
978
  return short ? `reopens ${reopen.text}` : `markets closed until ${reopen.text}`;
935
979
  default: {
@@ -939,6 +983,53 @@ function marketText(market: ReportMarket, now: number, short: boolean, local: bo
939
983
  }
940
984
  }
941
985
 
986
+ /** Whether every market of a mixed report reads the same (`markets closed until Mon`): one line then says it for all. */
987
+ function sameMarketText(markets: readonly VenueMarket[], now: number): boolean {
988
+ return new Set(markets.map((market) => marketText(market, now, false, false))).size === 1;
989
+ }
990
+
991
+ /**
992
+ * Where each market of a report that mixes them stands, one after another:
993
+ * the open ones first, then those in an extended session, then the closed ones
994
+ * by when they open. `markets closed · LSE opens 08:00 UTC · US 13:30 UTC`
995
+ * while all are closed, else each its own (`LSE open · US pre-market, opens
996
+ * 13:30 UTC`). A time is the regular session's open, as `marketText` says it;
997
+ * `short` leaves out `markets closed`.
998
+ */
999
+ function marketsText(markets: readonly VenueMarket[], now: number, short: boolean, local: boolean): string {
1000
+ const opensAt = (market: VenueMarket) => market.reopensAt ? Date.parse(market.reopensAt) : Number.POSITIVE_INFINITY;
1001
+ const rank = (market: VenueMarket) => market.state === "open" ? 0 : market.state === "closed" ? 2 : 1;
1002
+ const ordered = [...markets].sort((left, right) => rank(left) - rank(right) || opensAt(left) - opensAt(right));
1003
+ // `LSE opens 08:00 UTC · US 13:30 UTC`: a verb is said once for the timed opens that follow each other
1004
+ // with it; a week's first trade after a session's open says its own (`reopens 22:00 UTC`).
1005
+ let previousVerb: string | null = null;
1006
+ const parts = ordered.map((market) => {
1007
+ const reopen = reopenText(market, now, local);
1008
+ const verb = market.state === "closed" && reopen?.time ? market.firstTrade ? "reopens" : "opens" : null;
1009
+ const said = (() => {
1010
+ switch (market.state) {
1011
+ case "open":
1012
+ return `${market.market} open`;
1013
+ case "after-hours":
1014
+ return `${market.market} after hours`;
1015
+ case "pre-market":
1016
+ return reopen?.time ? `${market.market} pre-market, opens ${reopen.text}` : `${market.market} pre-market`;
1017
+ case "closed":
1018
+ if (!reopen) return `${market.market} closed`;
1019
+ if (!reopen.time) return `${market.market} closed until ${reopen.text}`;
1020
+ return `${market.market} ${verb === previousVerb ? "" : `${verb} `}${reopen.text}`;
1021
+ default: {
1022
+ const _exhaustive: never = market.state;
1023
+ return _exhaustive;
1024
+ }
1025
+ }
1026
+ })();
1027
+ previousVerb = verb;
1028
+ return said;
1029
+ });
1030
+ return ordered.every((market) => market.state === "closed") && !short ? ["markets closed", ...parts].join(" · ") : parts.join(" · ");
1031
+ }
1032
+
942
1033
  interface StatusLineDetail {
943
1034
  /** Leave out the oldest observation. */
944
1035
  asOf?: "short";
@@ -970,13 +1061,16 @@ function statusLineParts(freshness: ReportFreshness, detail: StatusLineDetail =
970
1061
  const undated = detail.date === "none";
971
1062
  return [
972
1063
  ...(freshness.sources?.length ? sourcesAsOfParts(freshness, freshness.sources, undated)
1064
+ : freshness.unreached && !freshness.asOf ? []
973
1065
  : [asOfText(freshness, detail.asOf === "short", local, undated)]),
974
1066
  ...(freshness.schedule && detail.schedule !== "none"
975
1067
  ? [typeof detail.schedule === "number" ? freshness.scheduleVariants?.[detail.schedule] ?? freshness.schedule : freshness.schedule] : []),
976
1068
  ...(freshness.oldestAgeMinutes != null ? [`oldest ${ageText(freshness.oldestAgeMinutes)}`] : []),
977
1069
  ...(freshness.savedAt ? [savedCopyText(freshness.savedAt, freshness.retrievedAt, local)]
978
1070
  : [statusText(detail.basis === "none" ? { ...freshness, basis: undefined } : freshness, detail.status === "short")].filter(Boolean)),
979
- ...(freshness.market && detail.market !== "none" ? [marketText(freshness.market, now, detail.market === "short", local)] : []),
1071
+ ...(detail.market === "none" ? []
1072
+ : freshness.markets?.length ? [marketsText(freshness.markets, now, detail.market === "short", local)]
1073
+ : freshness.market ? [marketText(freshness.market, now, detail.market === "short", local)] : []),
980
1074
  ...(freshness.note && detail.note !== "none" ? [typeof detail.note === "number" ? freshness.noteVariants?.[detail.note] ?? freshness.note : freshness.note] : []),
981
1075
  ];
982
1076
  }
@@ -1174,7 +1268,8 @@ export function captureStatusLine({ report: loaded, selfDated, quoted, rendered
1174
1268
  }
1175
1269
  if (report && loaded?.declaresData) return sourced(report);
1176
1270
  if (quoted) return plain(quoted, "quotes");
1177
- if (report && (report.status !== "unreported" || report.ageOnly)) return sourced(report);
1271
+ // A report that names no feed but dates its data by a session's close says so too: a board's figures outside the session.
1272
+ if (report && (report.status !== "unreported" || report.ageOnly || report.asOfClose)) return sourced(report);
1178
1273
  return plain(rendered(), null);
1179
1274
  }
1180
1275
 
@@ -234,9 +234,10 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
234
234
  bloomberg: ["RV"],
235
235
  },
236
236
  EQS: {
237
- summary: "Screen covered stocks on valuation, growth, margins, liquidity, volatility, short interest, insider activity and 13F holders, then rank the matches by any metric. "
238
- + "ATR% is the 14-session average true range as a percent of the last close. IV rank is a rank, not an IV percentile: 0 is the lowest 30-day implied volatility of the past 52 weeks and 100 the highest.",
239
- usage: ["EQS"],
237
+ summary: "Screen covered stocks on valuation, growth, margins, liquidity, volatility, technicals, float and ownership, short interest, insider activity and 13F holders, then rank the matches by any metric. "
238
+ + "ATR% is the 14-session average true range as a percent of the last close. IV rank is a rank, not an IV percentile: 0 is the lowest 30-day implied volatility of the past 52 weeks and 100 the highest. IV percentile, IV30 change in vol points, HV20 and HV rank screen premium to sell. "
239
+ + "Technical fields read the last completed session: RSI 14, price vs SMA 20, 50 and 200, trading days since a MACD or golden cross and since a new 20-day or 52-week high or low, and Bollinger width percentile (0 is a six-month squeeze). Ideas holds ready technical screens.",
240
+ usage: ["EQS", "gloom fn EQS --preset golden-cross"],
240
241
  keys: [key("a", "dd criterion"), key("m", "etric"), key("t", "check ticker"), key("s", "ave screen"), key("o", "pen research")],
241
242
  data: same("Daily snapshot, statements as filed"),
242
243
  bloomberg: ["EQS"],
@@ -285,8 +286,10 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
285
286
  },
286
287
  CSP: {
287
288
  summary: "Which names pay most to sell a put? For each, the put nearest a delta (0.30) on the expiry nearest a date or a number of days out (30), "
288
- + "ranked by annualised yield on cash at the bid, with % out of the money, delta, IV rank, the spread (marked wide, never left out) and an earnings flag.",
289
- usage: ["CSP JPM, GS, KO", "gloom fn CSP JPM GS KO AAPL --delta 0.20 --days 45"],
289
+ + "ranked by annualised yield on cash at the bid, with % out of the money, delta, IV rank, the spread (marked wide, never left out) and an earnings flag. "
290
+ + "--strategy screens covered calls, verticals, iron condors, straddles, strangles and calendars the same way, with the trade, credit or debit, "
291
+ + "max gain and loss per contract, break-evens, probability of profit, and an income trade's annualised return or a debit trade's reward to risk.",
292
+ usage: ["CSP JPM, GS, KO", "gloom fn CSP JPM GS KO AAPL --delta 0.20 --days 45", "gloom fn CSP JPM GS KO --strategy iron-condor"],
290
293
  keys: [key("Enter", " open in OSA")],
291
294
  data: OPTIONS,
292
295
  bloomberg: [],
@@ -713,8 +716,8 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
713
716
 
714
717
  // Watch markets
715
718
  MOST: {
716
- summary: "Today's top gainers, losers, most active and trending tickers with price, change, volume against average and market cap, and the pre-market and after-hours movers. On Pro, the gaps at the open.",
717
- usage: ["MOST"],
719
+ summary: "Today's top gainers, losers, most active and trending tickers with price, change, volume against average and market cap, and the pre-market and after-hours movers. On Pro, the gaps at the open. Min float keeps the names with at least that many shares in the float.",
720
+ usage: ["MOST", "gloom fn MOST --list gainers --min-float 10M"],
718
721
  keys: [TABS, OPEN],
719
722
  data: { free: DELAYED, pro: REAL_TIME },
720
723
  bloomberg: ["MOST"],
@@ -734,10 +737,10 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
734
737
  bloomberg: ["IMAP"],
735
738
  },
736
739
  MEMB: {
737
- summary: "ETF holdings with weights, shares, member returns, daily contributions and index changes. SPX and SPY use IVV holdings.",
738
- usage: ["MEMB", "MEMB SPY", "MEMB IWM"],
740
+ summary: "ETF holdings with weights, shares, member returns, daily contributions, breadth and index changes. SPX and ^SPX use IVV holdings.",
741
+ usage: ["MEMB", "MEMB SPX", "MEMB ^RUT", "gloom fn MEMB SPX --tab breadth"],
739
742
  keys: [TABS, OPEN, MEMBERS_MENU],
740
- data: same("Dated fund holdings and partial delayed member returns. Nasdaq-100 is not covered."),
743
+ data: same("Dated holdings and member returns. Breadth history uses current members (survivorship bias). Nasdaq-100 is not covered."),
741
744
  bloomberg: ["MEMB", "MRR", "IMOV"],
742
745
  },
743
746
  THEM: {
@@ -894,10 +897,17 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
894
897
  data: US_SCANNER,
895
898
  bloomberg: [],
896
899
  },
900
+ SCAN: {
901
+ summary: "Your own intraday scan of US stocks over all listings, an index, a sector or a watchlist: moves over the last minutes, volume spikes against the average pace, new session highs and lows, VWAP crosses and gaps, above price, market cap and volume floors. Matches refresh through the session, and new ones can alert.",
902
+ usage: ["SCAN"],
903
+ keys: [TABS, OPEN, key("a", "dd condition"), key("s", "ave scan")],
904
+ data: US_SCANNER,
905
+ bloomberg: [],
906
+ },
897
907
  FLOW: {
898
- summary: "Sweeps, blocks and large premium prints as they hit the tape, with ticker, strike, expiry and premium.",
899
- usage: ["FLOW"],
900
- keys: [OPEN],
908
+ summary: "Sweeps, blocks and large premium prints, and the session's net premium tide.",
909
+ usage: ["FLOW", "FLOW NVDA"],
910
+ keys: [TABS, OPEN],
901
911
  data: pro(REAL_TIME),
902
912
  access: "pro",
903
913
  bloomberg: ["FLOW"],