@gloom-sh/terminal 0.18.5 → 0.19.1

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 (570) 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 +163 -8
  5. package/src/api-client/app-attention.ts +3 -0
  6. package/src/api-client/beneficial-owners.ts +3 -0
  7. package/src/api-client/company-kpis.ts +3 -0
  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 +19 -7
  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/hiring.ts +3 -0
  14. package/src/api-client/index.ts +15 -0
  15. package/src/api-client/ipo.ts +24 -1
  16. package/src/api-client/market-discovery.ts +10 -0
  17. package/src/api-client/market-movers.ts +7 -0
  18. package/src/api-client/members.ts +1 -1
  19. package/src/api-client/mna.ts +3 -0
  20. package/src/api-client/paths.ts +9 -1
  21. package/src/api-client/perps.ts +43 -0
  22. package/src/api-client/research-activity.ts +3 -2
  23. package/src/api-client/roadmap.ts +85 -0
  24. package/src/api-client/types.ts +82 -2
  25. package/src/app/pane-runtime/plugin-bindings.ts +9 -5
  26. package/src/app/runtime/broker-import.ts +0 -2
  27. package/src/app/runtime/plugin-bindings.ts +73 -56
  28. package/src/architecture/core-builtin-allowlist.json +2 -2
  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/market.ts +107 -38
  35. package/src/cli/commands/news-search.ts +22 -0
  36. package/src/cli/commands/options-chain.ts +48 -7
  37. package/src/cli/commands/options-leaps.ts +9 -3
  38. package/src/cli/commands/overview.ts +147 -32
  39. package/src/cli/commands/search.ts +21 -1
  40. package/src/cli/commands/themes.ts +11 -2
  41. package/src/cli/commands/ticker.ts +87 -36
  42. package/src/cli/company-name-hint.ts +41 -0
  43. package/src/cli/earnings-calendar.ts +1 -1
  44. package/src/cli/errors.ts +25 -2
  45. package/src/cli/glossary.ts +31 -2
  46. package/src/cli/history-rows.ts +57 -9
  47. package/src/cli/index-roots.ts +0 -7
  48. package/src/cli/index.ts +2 -0
  49. package/src/cli/listing-arg.ts +235 -60
  50. package/src/cli/output-file.ts +68 -0
  51. package/src/cli/pane-functions/capabilities.ts +4 -0
  52. package/src/cli/pane-functions/catalog.ts +80 -7
  53. package/src/cli/pane-functions/discovery.ts +21 -1
  54. package/src/cli/pane-functions/dom.ts +13 -3
  55. package/src/cli/pane-functions/freshness.ts +93 -4
  56. package/src/cli/pane-functions/function-help.ts +20 -10
  57. package/src/cli/pane-functions/headless.ts +17 -7
  58. package/src/cli/pane-functions/index.ts +54 -16
  59. package/src/cli/pane-functions/market-session.ts +66 -4
  60. package/src/cli/pane-functions/options.ts +19 -1
  61. package/src/cli/pane-functions/resolver.ts +19 -8
  62. package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
  63. package/src/cli/pane-functions/screenshot-types.ts +5 -0
  64. package/src/cli/quote-answer.ts +22 -11
  65. package/src/cli/saved-copy-persistence.ts +88 -0
  66. package/src/cli/ticker-resolution.ts +3 -2
  67. package/src/components/chart/composite/composite-chart.tsx +4 -0
  68. package/src/components/chart/composite/interactions.ts +6 -0
  69. package/src/components/chart/composite/legend.tsx +45 -7
  70. package/src/components/chart/composite/panel-gestures.ts +33 -0
  71. package/src/components/chart/composite/panel-surface.tsx +52 -3
  72. package/src/components/chart/composite/rasterizer.ts +24 -13
  73. package/src/components/chart/composite/scene.ts +39 -4
  74. package/src/components/chart/composite/series-cues.ts +14 -0
  75. package/src/components/chart/composite/text-renderer.ts +9 -2
  76. package/src/components/chart/composite/tool-catalog.ts +36 -0
  77. package/src/components/chart/composite/tools.ts +203 -44
  78. package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
  79. package/src/components/command-bar/assist/inventory.ts +2 -1
  80. package/src/components/command-bar/commands/direct/index.ts +28 -13
  81. package/src/components/command-bar/list/model.ts +5 -0
  82. package/src/components/command-bar/pane-templates/items.ts +3 -2
  83. package/src/components/command-bar/routes/root/runtime.ts +6 -7
  84. package/src/components/command-bar/selection-runtime.ts +52 -3
  85. package/src/components/command-bar/surface/index.tsx +2 -0
  86. package/src/components/command-bar/workflow/collection-actions.ts +3 -3
  87. package/src/components/layout/pane/capture-stamp.ts +2 -2
  88. package/src/components/layout/pane/footer/index.tsx +22 -6
  89. package/src/components/layout/pane/footer/model.ts +83 -15
  90. package/src/components/layout/pane/status-footer.ts +35 -2
  91. package/src/components/layout/status-widget-space.ts +9 -0
  92. package/src/components/onboarding/onboarding-wizard.tsx +4 -1
  93. package/src/components/onboarding/portfolio-step/positions-panel.tsx +12 -7
  94. package/src/components/onboarding/wizard-broker-sync.ts +0 -1
  95. package/src/components/onboarding/wizard-positions.ts +3 -3
  96. package/src/components/ticker/list-table-view.tsx +8 -21
  97. package/src/components/ui/choice-dialog.tsx +23 -18
  98. package/src/components/ui/choice-groups.ts +18 -0
  99. package/src/components/ui/data-table/opentui/index.tsx +9 -7
  100. package/src/components/ui/data-table/opentui/model.ts +26 -1
  101. package/src/components/ui/data-table/types.ts +2 -0
  102. package/src/components/ui/display.tsx +18 -3
  103. package/src/components/ui/icon.tsx +4 -1
  104. package/src/components/ui/list-view.tsx +8 -4
  105. package/src/components/ui/query-bar-keys.tsx +2 -0
  106. package/src/components/ui/query-bar.tsx +1 -0
  107. package/src/components/ui/select-button.tsx +5 -1
  108. package/src/components/ui/select-field.tsx +1 -0
  109. package/src/components/ui/table-layout.ts +8 -5
  110. package/src/core/app-runtime.ts +2 -0
  111. package/src/core/app-services.ts +2 -2
  112. package/src/data/config/chart-settings.ts +1 -1
  113. package/src/data/json-ticker-repository.ts +17 -8
  114. package/src/data/plugin-cache.ts +5 -3
  115. package/src/data/saved-copies.ts +8 -0
  116. package/src/data/ticker-repository.ts +16 -9
  117. package/src/data/ticker-writes.ts +81 -0
  118. package/src/data/ttl-cache.ts +165 -0
  119. package/src/docs/snapshot.json +103 -142
  120. package/src/i18n/es.ts +20 -6
  121. package/src/i18n/ja.ts +20 -6
  122. package/src/i18n/ko.ts +20 -6
  123. package/src/i18n/zh-cn.ts +20 -6
  124. package/src/i18n/zh-tw.ts +20 -6
  125. package/src/market-data/depositary-pair.ts +27 -3
  126. package/src/market-data/fund-facts.ts +50 -0
  127. package/src/market-data/market/change-basis.ts +16 -3
  128. package/src/market-data/market/format.ts +25 -0
  129. package/src/market-data/market/freshness.ts +2 -1
  130. package/src/market-data/options-alternatives.ts +81 -4
  131. package/src/market-data/quotes/metadata.ts +7 -0
  132. package/src/news/aggregator.ts +119 -9
  133. package/src/news/cloud-session.ts +21 -0
  134. package/src/news/hooks.ts +1 -0
  135. package/src/news/news-model.ts +1 -0
  136. package/src/news/types.ts +17 -0
  137. package/src/plugins/builtin/alerts/alert-engine.ts +20 -1
  138. package/src/plugins/builtin/alerts/alert-log.ts +33 -0
  139. package/src/plugins/builtin/alerts/calendar-events.ts +10 -4
  140. package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
  141. package/src/plugins/builtin/alerts/cli.ts +362 -80
  142. package/src/plugins/builtin/alerts/command.ts +25 -1
  143. package/src/plugins/builtin/alerts/event-rows.ts +24 -3
  144. package/src/plugins/builtin/alerts/events-pane.tsx +34 -10
  145. package/src/plugins/builtin/alerts/fired-log.ts +73 -9
  146. package/src/plugins/builtin/alerts/format.ts +75 -5
  147. package/src/plugins/builtin/alerts/headless.ts +34 -12
  148. package/src/plugins/builtin/alerts/history-rows.ts +3 -2
  149. package/src/plugins/builtin/alerts/history.ts +1 -1
  150. package/src/plugins/builtin/alerts/index.tsx +79 -16
  151. package/src/plugins/builtin/alerts/metric-command.ts +77 -4
  152. package/src/plugins/builtin/alerts/metric-data.ts +54 -13
  153. package/src/plugins/builtin/alerts/metric-model.ts +163 -14
  154. package/src/plugins/builtin/alerts/metric-parity-fixture.json +1 -1
  155. package/src/plugins/builtin/alerts/pane.tsx +61 -23
  156. package/src/plugins/builtin/alerts/quotes.ts +6 -0
  157. package/src/plugins/builtin/alerts/storage.ts +12 -8
  158. package/src/plugins/builtin/alerts/types.ts +4 -0
  159. package/src/plugins/builtin/analytics/index.tsx +2 -1
  160. package/src/plugins/builtin/analytics/risk-client.ts +16 -5
  161. package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
  162. package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
  163. package/src/plugins/builtin/analytics/risk-model.ts +55 -9
  164. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
  165. package/src/plugins/builtin/attention/index.tsx +2 -1
  166. package/src/plugins/builtin/attention/listing.ts +14 -0
  167. package/src/plugins/builtin/broker-manager/index.tsx +7 -3
  168. package/src/plugins/builtin/buildout/cells.tsx +12 -4
  169. package/src/plugins/builtin/buildout/format.ts +38 -0
  170. package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
  171. package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
  172. package/src/plugins/builtin/buildout/table-model.ts +23 -2
  173. package/src/plugins/builtin/builtin-plugin-meta.ts +6 -2
  174. package/src/plugins/builtin/cds/client.ts +142 -30
  175. package/src/plugins/builtin/cds/headless.ts +35 -8
  176. package/src/plugins/builtin/cds/model.ts +145 -18
  177. package/src/plugins/builtin/cds/pane.tsx +16 -5
  178. package/src/plugins/builtin/changelog/index.tsx +9 -6
  179. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +3 -0
  180. package/src/plugins/builtin/chart-composer/cli-options.ts +4 -0
  181. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -0
  182. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -2
  183. package/src/plugins/builtin/chart-composer/follow-binding.ts +14 -2
  184. package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -1
  185. package/src/plugins/builtin/chart-composer/headless.ts +6 -1
  186. package/src/plugins/builtin/chart-composer/index.tsx +5 -6
  187. package/src/plugins/builtin/chart-composer/pane.tsx +37 -8
  188. package/src/plugins/builtin/chart-composer/settings.ts +27 -0
  189. package/src/plugins/builtin/chat/content/command-suggestions.ts +1 -0
  190. package/src/plugins/builtin/chat/controller/index.ts +5 -1
  191. package/src/plugins/builtin/chat/controller/notifications.ts +33 -3
  192. package/src/plugins/builtin/chat/controller/state.ts +25 -2
  193. package/src/plugins/builtin/chat/controller/unread-people.ts +89 -23
  194. package/src/plugins/builtin/chat/controller/utils.ts +7 -2
  195. package/src/plugins/builtin/chat/pane-links/commands.ts +7 -1
  196. package/src/plugins/builtin/chat/status-preview.ts +79 -0
  197. package/src/plugins/builtin/chat/status-widget.tsx +147 -10
  198. package/src/plugins/builtin/chat/unread-badge.ts +51 -10
  199. package/src/plugins/builtin/clinical-trials/client.ts +49 -4
  200. package/src/plugins/builtin/clinical-trials/model.ts +86 -31
  201. package/src/plugins/builtin/clinical-trials/pane.tsx +61 -49
  202. package/src/plugins/builtin/clinical-trials/sponsor-listing.ts +90 -0
  203. package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +95 -15
  204. package/src/plugins/builtin/clinical-trials/trial-pages.ts +50 -0
  205. package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
  206. package/src/plugins/builtin/company-attention/building.tsx +5 -1
  207. package/src/plugins/builtin/company-attention/client.ts +8 -9
  208. package/src/plugins/builtin/company-attention/evidence.ts +4 -1
  209. package/src/plugins/builtin/company-attention/headless.ts +2 -1
  210. package/src/plugins/builtin/company-attention/moves.tsx +5 -1
  211. package/src/plugins/builtin/company-attention/pane.tsx +12 -2
  212. package/src/plugins/builtin/company-attention/signals.tsx +5 -1
  213. package/src/plugins/builtin/company-kpis/headless.ts +8 -3
  214. package/src/plugins/builtin/company-kpis/model.ts +73 -5
  215. package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
  216. package/src/plugins/builtin/composite-plugins.ts +2 -1
  217. package/src/plugins/builtin/correlation/headless.ts +13 -5
  218. package/src/plugins/builtin/correlation/history.ts +22 -0
  219. package/src/plugins/builtin/cot/client.ts +22 -18
  220. package/src/plugins/builtin/cot/headless.ts +15 -10
  221. package/src/plugins/builtin/cot/model.ts +14 -1
  222. package/src/plugins/builtin/cot/pane.tsx +22 -14
  223. package/src/plugins/builtin/credit-boards/client.ts +6 -10
  224. package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
  225. package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
  226. package/src/plugins/builtin/credit-conditions/model.ts +4 -0
  227. package/src/plugins/builtin/credit-conditions/series.ts +3 -1
  228. package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
  229. package/src/plugins/builtin/credit-documents/export.ts +173 -0
  230. package/src/plugins/builtin/credit-documents/headless.ts +10 -10
  231. package/src/plugins/builtin/credit-documents/model.ts +104 -14
  232. package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
  233. package/src/plugins/builtin/custom-view/sources.ts +2 -0
  234. package/src/plugins/builtin/dividend-yield/client.ts +131 -23
  235. package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
  236. package/src/plugins/builtin/dividend-yield/model.ts +8 -5
  237. package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
  238. package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
  239. package/src/plugins/builtin/dividend-yield/types.ts +20 -2
  240. package/src/plugins/builtin/dividend-yield/view.ts +30 -2
  241. package/src/plugins/builtin/docs/targets.ts +5 -1
  242. package/src/plugins/builtin/doe/headless.ts +3 -2
  243. package/src/plugins/builtin/doe/pane.tsx +13 -3
  244. package/src/plugins/builtin/earnings/board-model.ts +16 -15
  245. package/src/plugins/builtin/earnings/board.tsx +62 -71
  246. package/src/plugins/builtin/earnings/headless.ts +40 -4
  247. package/src/plugins/builtin/earnings/scope.ts +31 -43
  248. package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
  249. package/src/plugins/builtin/earnings-calls/data.ts +18 -6
  250. package/src/plugins/builtin/earnings-calls/format.ts +31 -2
  251. package/src/plugins/builtin/earnings-calls/headless.ts +20 -5
  252. package/src/plugins/builtin/earnings-calls/model.ts +6 -1
  253. package/src/plugins/builtin/earnings-calls/pane.tsx +12 -4
  254. package/src/plugins/builtin/econ/calendar-model.ts +48 -1
  255. package/src/plugins/builtin/econ/calendar-source.ts +4 -2
  256. package/src/plugins/builtin/econ/detail-view.tsx +2 -2
  257. package/src/plugins/builtin/econ/figures.ts +48 -0
  258. package/src/plugins/builtin/econ/index.tsx +14 -5
  259. package/src/plugins/builtin/econ/print-watch.ts +3 -1
  260. package/src/plugins/builtin/econ/types.ts +2 -0
  261. package/src/plugins/builtin/econ-statistics/client.ts +11 -0
  262. package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
  263. package/src/plugins/builtin/econ-statistics/headless.ts +16 -6
  264. package/src/plugins/builtin/econ-statistics/pane.tsx +8 -4
  265. package/src/plugins/builtin/econ-statistics/stats.ts +39 -9
  266. package/src/plugins/builtin/equity-screener/categories.ts +179 -0
  267. package/src/plugins/builtin/equity-screener/client.ts +4 -2
  268. package/src/plugins/builtin/equity-screener/headless.ts +144 -13
  269. package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
  270. package/src/plugins/builtin/equity-screener/model.ts +99 -10
  271. package/src/plugins/builtin/equity-screener/pane.tsx +68 -13
  272. package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
  273. package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
  274. package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
  275. package/src/plugins/builtin/fx-matrix/client.ts +6 -3
  276. package/src/plugins/builtin/fx-matrix/headless.ts +1 -1
  277. package/src/plugins/builtin/fx-matrix/index.tsx +4 -2
  278. package/src/plugins/builtin/fx-matrix/live-legs.ts +42 -3
  279. package/src/plugins/builtin/gpu/headless.ts +8 -2
  280. package/src/plugins/builtin/help/function-index.ts +4 -1
  281. package/src/plugins/builtin/help/index.tsx +62 -59
  282. package/src/plugins/builtin/help/shortcut-model.ts +1 -1
  283. package/src/plugins/builtin/help/shortcut-table.tsx +5 -6
  284. package/src/plugins/builtin/help/table-cells.tsx +13 -2
  285. package/src/plugins/builtin/holders/beneficial-client.ts +5 -1
  286. package/src/plugins/builtin/holders/beneficial-view.tsx +3 -0
  287. package/src/plugins/builtin/holders/fund-holders.ts +51 -0
  288. package/src/plugins/builtin/holders/headless.ts +22 -3
  289. package/src/plugins/builtin/holders/pane.tsx +3 -0
  290. package/src/plugins/builtin/holders/report-rows.ts +4 -1
  291. package/src/plugins/builtin/insider/headless.ts +2 -2
  292. package/src/plugins/builtin/ipo-calendar/client.ts +18 -2
  293. package/src/plugins/builtin/ipo-calendar/headless.ts +75 -11
  294. package/src/plugins/builtin/ipo-calendar/listing-ipo.ts +160 -0
  295. package/src/plugins/builtin/ipo-calendar/model.ts +98 -2
  296. package/src/plugins/builtin/iv-history/client.ts +52 -11
  297. package/src/plugins/builtin/iv-history/format.ts +36 -23
  298. package/src/plugins/builtin/iv-history/headless.ts +33 -18
  299. package/src/plugins/builtin/iv-history/index.tsx +2 -2
  300. package/src/plugins/builtin/iv-history/model.ts +163 -27
  301. package/src/plugins/builtin/iv-history/pane.tsx +10 -6
  302. package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
  303. package/src/plugins/builtin/iv-history/universe.ts +5 -1
  304. package/src/plugins/builtin/jobs/client.ts +25 -29
  305. package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
  306. package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
  307. package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
  308. package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
  309. package/src/plugins/builtin/macro-day/headless.ts +12 -5
  310. package/src/plugins/builtin/macro-day/index.tsx +1 -1
  311. package/src/plugins/builtin/macro-day/model.ts +39 -5
  312. package/src/plugins/builtin/macro-day/pane.tsx +27 -19
  313. package/src/plugins/builtin/macro-day/release-table.ts +2 -2
  314. package/src/plugins/builtin/market-heatmap/data.ts +8 -33
  315. package/src/plugins/builtin/market-movers/client.ts +27 -7
  316. package/src/plugins/builtin/market-movers/headless.ts +34 -12
  317. package/src/plugins/builtin/market-movers/index.tsx +26 -14
  318. package/src/plugins/builtin/market-movers/min-float.ts +74 -0
  319. package/src/plugins/builtin/market-movers/model.ts +4 -1
  320. package/src/plugins/builtin/market-movers/screener.ts +22 -4
  321. package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
  322. package/src/plugins/builtin/market-movers/session-table.ts +4 -3
  323. package/src/plugins/builtin/market-movers/table.ts +17 -5
  324. package/src/plugins/builtin/members/breadth-pane.tsx +2 -1
  325. package/src/plugins/builtin/mna/headless.ts +2 -0
  326. package/src/plugins/builtin/mna/pane.tsx +3 -1
  327. package/src/plugins/builtin/news/headless.ts +3 -1
  328. package/src/plugins/builtin/news/index.tsx +4 -0
  329. package/src/plugins/builtin/news/wire/categories.ts +19 -3
  330. package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
  331. package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
  332. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
  333. package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
  334. package/src/plugins/builtin/openfda/client.ts +14 -2
  335. package/src/plugins/builtin/openfda/index.tsx +3 -2
  336. package/src/plugins/builtin/openfda/model.ts +9 -0
  337. package/src/plugins/builtin/openfda/pane.tsx +42 -6
  338. package/src/plugins/builtin/options/analytics.ts +29 -5
  339. package/src/plugins/builtin/options/enrichment.ts +17 -5
  340. package/src/plugins/builtin/options/table.ts +5 -2
  341. package/src/plugins/builtin/options/types.ts +2 -0
  342. package/src/plugins/builtin/options/view.tsx +17 -4
  343. package/src/plugins/builtin/options-positioning/client.ts +11 -0
  344. package/src/plugins/builtin/options-positioning/headless.ts +21 -8
  345. package/src/plugins/builtin/options-positioning/index.tsx +1 -1
  346. package/src/plugins/builtin/options-positioning/model.ts +78 -9
  347. package/src/plugins/builtin/options-positioning/pane.tsx +21 -6
  348. package/src/plugins/builtin/options-scenario/client.ts +116 -47
  349. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
  350. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
  351. package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
  352. package/src/plugins/builtin/options-scenario/csp.ts +8 -2
  353. package/src/plugins/builtin/options-scenario/index.tsx +9 -7
  354. package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
  355. package/src/plugins/builtin/pe-band/model.ts +12 -49
  356. package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
  357. package/src/plugins/builtin/perps/cascade.ts +236 -0
  358. package/src/plugins/builtin/perps/client.ts +56 -2
  359. package/src/plugins/builtin/perps/headless.ts +65 -9
  360. package/src/plugins/builtin/perps/index.tsx +7 -5
  361. package/src/plugins/builtin/perps/model.ts +18 -4
  362. package/src/plugins/builtin/perps/pane.tsx +19 -22
  363. package/src/plugins/builtin/perps/status-line.ts +25 -0
  364. package/src/plugins/builtin/plugin-module.ts +5 -1
  365. package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
  366. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
  367. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
  368. package/src/plugins/builtin/portfolio-list/cli/render.ts +7 -5
  369. package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
  370. package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -7
  371. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
  372. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
  373. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +0 -14
  374. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +5 -2
  375. package/src/plugins/builtin/portfolio-list/table.tsx +15 -9
  376. package/src/plugins/builtin/primary-dealers/client.ts +13 -38
  377. package/src/plugins/builtin/realized-vol/client.ts +13 -5
  378. package/src/plugins/builtin/realized-vol/evidence.ts +29 -4
  379. package/src/plugins/builtin/realized-vol/headless.ts +8 -4
  380. package/src/plugins/builtin/realized-vol/index.tsx +2 -2
  381. package/src/plugins/builtin/realized-vol/model.ts +37 -6
  382. package/src/plugins/builtin/realized-vol/pane.tsx +11 -9
  383. package/src/plugins/builtin/relative-rotation/client.ts +18 -4
  384. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  385. package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
  386. package/src/plugins/builtin/relative-rotation/model.ts +16 -40
  387. package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
  388. package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
  389. package/src/plugins/builtin/research/event-model.ts +40 -12
  390. package/src/plugins/builtin/research/headless.ts +1 -1
  391. package/src/plugins/builtin/research/index.tsx +7 -3
  392. package/src/plugins/builtin/research/relative-valuation-headless.ts +13 -26
  393. package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
  394. package/src/plugins/builtin/research/relative-valuation-pane.tsx +59 -20
  395. package/src/plugins/builtin/research/relative-valuation-peers.ts +217 -20
  396. package/src/plugins/builtin/research/relative-valuation-settings.ts +44 -0
  397. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
  398. package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
  399. package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
  400. package/src/plugins/builtin/risk-factors/data.ts +4 -2
  401. package/src/plugins/builtin/risk-factors/headless.ts +5 -2
  402. package/src/plugins/builtin/roadmap/index.tsx +28 -0
  403. package/src/plugins/builtin/roadmap/model.ts +67 -0
  404. package/src/plugins/builtin/roadmap/pane.tsx +244 -0
  405. package/src/plugins/builtin/scanner/flow-model.ts +50 -4
  406. package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
  407. package/src/plugins/builtin/scanner/flow-session.ts +146 -0
  408. package/src/plugins/builtin/scanner/headless.ts +204 -35
  409. package/src/plugins/builtin/scanner/index.ts +16 -5
  410. package/src/plugins/builtin/scanner/live-headless.ts +48 -5
  411. package/src/plugins/builtin/scanner/live-model.ts +11 -0
  412. package/src/plugins/builtin/scanner/live-pane.tsx +3 -3
  413. package/src/plugins/builtin/scanner/lock-note.ts +3 -2
  414. package/src/plugins/builtin/seasonality/headless.ts +10 -1
  415. package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
  416. package/src/plugins/builtin/sec/fund-facts.ts +116 -34
  417. package/src/plugins/builtin/sec/headless.ts +4 -2
  418. package/src/plugins/builtin/sec/index.tsx +3 -0
  419. package/src/plugins/builtin/series-inventory.ts +2 -0
  420. package/src/plugins/builtin/shared/cloud-resource.ts +16 -7
  421. package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
  422. package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
  423. package/src/plugins/builtin/shared/earnings-report.ts +2 -2
  424. package/src/plugins/builtin/shared/headless-market-data.ts +2 -2
  425. package/src/plugins/builtin/shared/job-posting.ts +1 -0
  426. package/src/plugins/builtin/shared/members-menu.tsx +3 -2
  427. package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
  428. package/src/plugins/builtin/shared/report-freshness.ts +11 -2
  429. package/src/plugins/builtin/shared/research-cells.tsx +1 -1
  430. package/src/plugins/builtin/shared/series-cache.ts +4 -4
  431. package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
  432. package/src/plugins/builtin/shared/ticker-company.ts +77 -0
  433. package/src/plugins/builtin/shared/use-quote-board.ts +2 -1
  434. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
  435. package/src/plugins/builtin/shared/volatility/pricing.ts +19 -0
  436. package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
  437. package/src/plugins/builtin/themes/model.ts +16 -7
  438. package/src/plugins/builtin/themes/pane.tsx +5 -5
  439. package/src/plugins/builtin/thirteenf/api.ts +12 -1
  440. package/src/plugins/builtin/thirteenf/data.ts +7 -7
  441. package/src/plugins/builtin/thirteenf/headless.ts +31 -4
  442. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
  443. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
  444. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
  445. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
  446. package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
  447. package/src/plugins/builtin/ticker-detail/overview/model.ts +11 -3
  448. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +2 -1
  449. package/src/plugins/builtin/ticker-detail/pane.tsx +14 -8
  450. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
  451. package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
  452. package/src/plugins/builtin/time-sales/pane.tsx +31 -19
  453. package/src/plugins/builtin/treasury-auctions/headless.ts +21 -12
  454. package/src/plugins/builtin/treasury-auctions/pane.tsx +9 -3
  455. package/src/plugins/builtin/treasury-daily/client.ts +41 -5
  456. package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
  457. package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
  458. package/src/plugins/builtin/treasury-daily/model.ts +50 -3
  459. package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
  460. package/src/plugins/builtin/vol-surface/client.ts +3 -13
  461. package/src/plugins/builtin/vol-surface/headless.ts +3 -3
  462. package/src/plugins/builtin/vol-surface/index.tsx +1 -1
  463. package/src/plugins/builtin/vol-surface/pane.tsx +7 -5
  464. package/src/plugins/builtin/volatility/index.tsx +2 -2
  465. package/src/plugins/builtin/volatility/pane.tsx +7 -4
  466. package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
  467. package/src/plugins/builtin/yield-curve/client.ts +61 -1
  468. package/src/plugins/builtin/yield-curve/headless.ts +9 -6
  469. package/src/plugins/builtin/yield-curve/index.tsx +34 -10
  470. package/src/plugins/builtin/yield-curve/swaps.tsx +9 -5
  471. package/src/plugins/catalog-browser.ts +2 -1
  472. package/src/plugins/catalog-manifest.ts +2 -1
  473. package/src/plugins/host-link.ts +1 -1
  474. package/src/plugins/marketplace/model.ts +18 -5
  475. package/src/portfolio/column-values.ts +11 -7
  476. package/src/portfolio/futures-positions.ts +6 -3
  477. package/src/portfolio/position-quantity.ts +15 -9
  478. package/src/remote/resources.ts +2 -1
  479. package/src/renderers/dom/data-table/row.tsx +26 -0
  480. package/src/renderers/dom/desktop/icons.tsx +7 -0
  481. package/src/renderers/dom/desktop/list-view.tsx +13 -10
  482. package/src/renderers/dom/desktop/query-bar.tsx +4 -2
  483. package/src/renderers/dom/desktop/select-field.tsx +4 -2
  484. package/src/renderers/dom/host/chart-surface.tsx +21 -0
  485. package/src/renderers/electrobun/bun/desktop/app-name.ts +3 -3
  486. package/src/renderers/electrobun/bun/desktop/backend.ts +21 -10
  487. package/src/renderers/electrobun/bun/desktop/host-requests.ts +15 -0
  488. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
  489. package/src/renderers/electrobun/bun/desktop/installer-folder.ts +731 -0
  490. package/src/renderers/electrobun/bun/desktop/relaunch.ts +102 -10
  491. package/src/renderers/electrobun/bun/desktop/update.ts +115 -14
  492. package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
  493. package/src/renderers/electrobun/bun/desktop/windows-script.ts +92 -0
  494. package/src/renderers/electrobun/bun/index.ts +26 -2
  495. package/src/renderers/electrobun/bun/window/create.ts +43 -4
  496. package/src/renderers/electrobun/bun/window/events.ts +20 -0
  497. package/src/renderers/electrobun/bun/window/windows-custom-chrome.ts +9 -2
  498. package/src/renderers/electrobun/bun/window/windows-native.ts +78 -0
  499. package/src/renderers/electrobun/bun/window/windows-quit.ts +57 -0
  500. package/src/renderers/electrobun/shared/app-name.ts +13 -0
  501. package/src/renderers/electrobun/shared/protocol.ts +12 -0
  502. package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
  503. package/src/renderers/electrobun/view/main.tsx +24 -1
  504. package/src/renderers/electrobun/view/news-source.ts +5 -1
  505. package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
  506. package/src/renderers/electrobun/view/ui-host.tsx +8 -0
  507. package/src/renderers/electrobun/view/view-ids.ts +85 -0
  508. package/src/renderers/opentui/start.tsx +5 -0
  509. package/src/series/registry.ts +1 -0
  510. package/src/series/types.ts +6 -0
  511. package/src/series/validate.ts +1 -0
  512. package/src/sources/gloomberb-cloud/fred-series.ts +3 -1
  513. package/src/sources/gloomberb-cloud/index.ts +43 -8
  514. package/src/sources/gloomberb-cloud/news.ts +47 -7
  515. package/src/sources/provider-router/financials.ts +15 -3
  516. package/src/sources/provider-router/index.ts +8 -5
  517. package/src/state/ticker-cleanup.ts +50 -0
  518. package/src/sync/controller.ts +4 -3
  519. package/src/sync/core-contributors.ts +90 -31
  520. package/src/telemetry/stall-reports-dom.ts +38 -0
  521. package/src/telemetry/stall-reports-node.ts +75 -0
  522. package/src/telemetry/stall-reports.ts +214 -0
  523. package/src/test-support/preload.ts +14 -0
  524. package/src/theme/themes.ts +10 -0
  525. package/src/tickers/company-name-listing.ts +53 -13
  526. package/src/tickers/company-name.ts +50 -4
  527. package/src/tickers/index-roots.ts +7 -0
  528. package/src/tickers/listing-fate.ts +2 -2
  529. package/src/tickers/listing-venues.ts +15 -3
  530. package/src/tickers/search/index.ts +6 -2
  531. package/src/tickers/search/ranking.ts +5 -1
  532. package/src/tickers/search/upsert.ts +13 -0
  533. package/src/tickers/terminal-codes.ts +19 -0
  534. package/src/tickers/ticker-changes.ts +8 -4
  535. package/src/time-series/alignment.ts +1 -1
  536. package/src/time-series/economic.ts +18 -4
  537. package/src/time-series/field-catalog.ts +1 -1
  538. package/src/time-series/filed-trailing-eps.ts +197 -0
  539. package/src/time-series/fundamentals.ts +44 -1
  540. package/src/time-series/ice-credit.ts +3 -0
  541. package/src/time-series/price-comparison.ts +30 -2
  542. package/src/time-series/resolve-context.ts +3 -1
  543. package/src/time-series/resolve.ts +56 -4
  544. package/src/time-series/session-bar.ts +11 -0
  545. package/src/time-series/spec.ts +3 -2
  546. package/src/time-series/studies.ts +8 -2
  547. package/src/time-series/total-return.ts +160 -0
  548. package/src/time-series/transforms.ts +2 -3
  549. package/src/time-series/types.ts +22 -1
  550. package/src/types/company-from.ts +40 -0
  551. package/src/types/data-provider.ts +7 -0
  552. package/src/types/financials.ts +59 -1
  553. package/src/types/headless.ts +27 -3
  554. package/src/types/news-source.ts +1 -0
  555. package/src/types/plugin.ts +9 -0
  556. package/src/ui/host.tsx +3 -0
  557. package/src/updater/failure.ts +4 -1
  558. package/src/utils/cli-output.ts +42 -1
  559. package/src/utils/crypto-pair.ts +165 -7
  560. package/src/utils/declared-dividends.ts +1 -1
  561. package/src/utils/forward-dividend.ts +2 -0
  562. package/src/utils/fundamentals.ts +60 -8
  563. package/src/utils/fx-market-hours.ts +26 -3
  564. package/src/utils/main-thread-stall.ts +35 -2
  565. package/src/utils/market-capitalization.ts +24 -1
  566. package/src/utils/price-history.ts +7 -1
  567. package/src/utils/shell-word.ts +8 -0
  568. package/src/utils/trailing-dividend.ts +53 -4
  569. package/src/version.ts +2 -2
  570. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
@@ -3,6 +3,7 @@ import type { CliCommandDef } from "../../types/plugin";
3
3
  import { TIME_RANGES, type TimeRange } from "../../time-series/range";
4
4
  import { yearToDateStartIndex } from "../../market-data/market/year-to-date";
5
5
  import type { EarningsEvent, QuoteBatchResult, QuoteSubscriptionTarget, SecFilingItem } from "../../types/data-provider";
6
+ import { companyDataNotes, type CompanyFrom } from "../../types/company-from";
6
7
  import type { NewsArticle, NewsFeed, NewsQuery } from "../../news/types";
7
8
  import type {
8
9
  AnalystResearchData,
@@ -12,7 +13,7 @@ import type {
12
13
  Quote,
13
14
  TickerFinancials,
14
15
  } from "../../types/financials";
15
- import { currencyPriceMinDigits, formatMarketPrice, formatMarketPriceWithCurrency, quoteFormatOptions, resolveAssetDisplayKind, withCurrencyMinorDigits } from "../../market-data/market/format";
16
+ import { currencyPriceMinDigits, formatMarketPrice, formatMarketPriceWithCurrency, penceFigure, quoteFormatOptions, resolveAssetDisplayKind, withCurrencyMinorDigits } from "../../market-data/market/format";
16
17
  import { INDEX_POINTS_EXPORT_UNIT, isIndexLevel, reportedQuoteVolume } from "../../market-data/market/index-level";
17
18
  import { changeBasisJson, changeBasisLabel, changeBasisNote, quoteChangeBasis, quotePreviousCloseDate, quoteSettleText } from "../../market-data/market/change-basis";
18
19
  import {
@@ -41,6 +42,7 @@ import {
41
42
  import { cliArrow, cliStyles, colorBySign, renderSection, renderStats } from "../../utils/cli-output";
42
43
  import { filledPeriodsNote, stalePeriodNote, statementHistoryNotes } from "../../utils/financial-statements";
43
44
  import { formatPerShareNumber } from "../../utils/reported-money";
45
+ import { isCurrencyPairListing } from "../../utils/fx-market-hours";
44
46
  import {
45
47
  analystTargetCurrency,
46
48
  formatAnalystPrice,
@@ -58,7 +60,7 @@ import {
58
60
  } from "../../market-data/options-alternatives";
59
61
  import {
60
62
  atReportTtmRate, cliFuturesContract, futuresContractMetrics, exportedDividendFundamentals, fundamentalsReportTables, loadDividendDistributions,
61
- loadReportBondFacts, renderFundamentalsReport, writesCurrencyCodes,
63
+ loadReportFundFacts, renderFundamentalsReport, writesCurrencyCodes,
62
64
  } from "./ticker";
63
65
  import { createBaseConverter } from "../base-converter";
64
66
  import { loadStatementFilings } from "../statement-filings";
@@ -75,6 +77,7 @@ import {
75
77
  loadOptionModelInputs,
76
78
  loadOptionsChainOpenInterest,
77
79
  chainCoinCurrency,
80
+ chainHasFilledIv,
78
81
  formatCoinPremiumCell,
79
82
  formatOptionDeltaCell,
80
83
  formatOptionDollarCell,
@@ -90,6 +93,7 @@ import {
90
93
  optionsBasisFields,
91
94
  optionsBasisFootnote,
92
95
  parseOptionExpiration,
96
+ takeExpirationOption,
93
97
  valueChainAtModelSpot,
94
98
  type OptionsChainBasis,
95
99
  } from "./options-chain";
@@ -139,6 +143,7 @@ import {
139
143
  historyPriceDecimals,
140
144
  historyRows,
141
145
  historyUnit,
146
+ quotedPriceDivisor,
142
147
  historyVolume,
143
148
  historyVolumeText,
144
149
  type HistoryRow,
@@ -153,7 +158,7 @@ import {
153
158
  symbolListNotes,
154
159
  type HistoryListRow,
155
160
  } from "../history-export";
156
- import { isCliFailure } from "../errors";
161
+ import { fail, isCliFailure, NO_DATA_CODE } from "../errors";
157
162
  import { mapWithConcurrency } from "../../utils/concurrency";
158
163
  import { MISSING_VOLUME_TEXT } from "../../utils/price-history-integrity";
159
164
  import { CRYPTO_BOARD_HINT, quoteNotes } from "./crypto-hints";
@@ -161,6 +166,7 @@ import { bareFuturesCode, futuresBoardContract } from "../../market-data/futures
161
166
  import { commodityNamedIn, commoditySearchName } from "../../market-data/commodity-names";
162
167
  import { newsEmptyMessage } from "./news-hints";
163
168
  import {
169
+ closestStoriesReason,
164
170
  commodityNewsRoute,
165
171
  commonWordCandidate,
166
172
  METALS_NEWS_TOPIC,
@@ -175,6 +181,7 @@ import {
175
181
  noMetalStoriesMessage,
176
182
  noStoriesMessage,
177
183
  quotedSearchCommand,
184
+ searchClosestNewsStories,
178
185
  searchNewsStories,
179
186
  wordMeansMore,
180
187
  } from "./news-search";
@@ -185,7 +192,7 @@ import { exportedFundamentals } from "../../utils/price-earnings";
185
192
  import { fundamentalsFreshness, fxPairFreshness, quotesFreshness, rowsFreshness, valuationFreshness } from "../freshness";
186
193
  import { fxRateNotes } from "../../plugins/builtin/shared/fx-rate-freshness";
187
194
  import { quoteBarNotes } from "../../market-data/quotes/intraday-bar";
188
- import { depositaryPairText, isReceiptSide, listingDepositaryPair } from "../../market-data/depositary-pair";
195
+ import { cedearRatioText, depositaryPairText, isReceiptSide, listingCedearRatio, listingDepositaryPair } from "../../market-data/depositary-pair";
189
196
  import { isPesoDollarPair, loadPesoDollarRates, pesoDollarRateLines, pesoDollarRatesJson } from "../peso-dollar-rates";
190
197
  import { atRegularSessionPrice, regularSessionValuationPrice } from "../../market-data/quotes/regular-session-valuation";
191
198
  import { viewMarketCapitalization } from "../../utils/market-capitalization";
@@ -195,6 +202,7 @@ import {
195
202
  cloudNewsFreshness,
196
203
  cloudRealtimeAccess,
197
204
  REPORTED_DATA,
205
+ SEC_FILING_ROWS,
198
206
  SEC_FILINGS,
199
207
  } from "../../plugins/builtin/shared/report-freshness";
200
208
  import {
@@ -215,6 +223,7 @@ import {
215
223
  type ResolvedEarningsEvent,
216
224
  } from "../../plugins/builtin/shared/earnings-calendar";
217
225
  import {
226
+ coinListingNotes,
218
227
  EXCHANGE_OPTION,
219
228
  listingHeading,
220
229
  listingIdentity,
@@ -237,7 +246,7 @@ import {
237
246
  type ListingIdentity,
238
247
  } from "../listing-arg";
239
248
  import { bareListingNote, listingFateNotes, noLongerTradingNote, tradingListing } from "../../tickers/listing-fate";
240
- import { isYieldIndexSymbol } from "../index-roots";
249
+ import { isYieldIndexSymbol } from "../../tickers/index-roots";
241
250
  import {
242
251
  analyzeTaxEquivalent, distributionBasis, loadTreasuryTenors, parseTaxRates, TAX_RATE_HELP_OPTIONS, taxEquivalentJson, type TaxRates,
243
252
  } from "../../market-data/tax-equivalent";
@@ -303,6 +312,7 @@ import {
303
312
  unvaluedHoldersNote,
304
313
  } from "../../plugins/builtin/holders/report-rows";
305
314
  import { fetchBeneficialOwners } from "../../plugins/builtin/holders/beneficial-client";
315
+ import { fundHoldersAnswer } from "../../plugins/builtin/holders/fund-holders";
306
316
  import { centralBankEventsMessage } from "../central-bank-events";
307
317
  import { classSharesAsOf, classSharesToday } from "../../plugins/builtin/holders/client";
308
318
  import {
@@ -465,7 +475,8 @@ const QUOTE_LEAD_COLUMNS = [
465
475
  row.error && !row.price
466
476
  // A typo is not an outage: say what is wrong with the symbol itself.
467
477
  ? isNotATickerMessage(row.error) ? cliStyles.warning("not a ticker") : cliStyles.danger("unavailable")
468
- : yieldLevelCell(row.price, row)
478
+ // A London line adds the pence it trades in, as the exchange and RNS write it, muted as a table cell's note is: £6.308 630.8p.
479
+ : `${yieldLevelCell(row.price, row)}${row.pence ? ` ${cliStyles.muted(row.pence)}` : ""}`
469
480
  ),
470
481
  },
471
482
  {
@@ -729,10 +740,12 @@ function quoteRows(results: QuoteCliRecord[], now = Date.now()) {
729
740
  // A price in cents says what it is per, as the contract terms word it: 314.95¢/lb.
730
741
  const per = display.price != null ? futuresPricePer(result.futuresContract, quote?.currency) : "";
731
742
  const previousClose = display.price != null && display.change != null ? display.price - display.change : quote?.previousClose;
743
+ const last = price(display.price);
732
744
  return {
733
745
  symbol: result.target.symbol,
734
746
  name: quote?.name || result.listing?.name || "",
735
- price: `${price(display.price)}${per}`,
747
+ price: `${last}${per}`,
748
+ pence: penceFigure(display.price, quote, /\.(\d+)/.exec(last)?.[1]?.length ?? 0),
736
749
  rawPrice: display.price,
737
750
  priceBasis: quote?.priceBasis ?? null,
738
751
  instrumentType: quote?.instrumentType ?? null,
@@ -904,7 +917,7 @@ function corporateActionRows(data: CorporateActionsData) {
904
917
  ...declaredDividends(data).map((event) => ({
905
918
  type: "dividend",
906
919
  date: event.exDate,
907
- detail: `declared ${currency ? formatDistributionAmount(event.amount, currency) : cleanDecimal(event.amount)}`
920
+ detail: `declared ${event.special ? "special " : ""}${currency ? formatDistributionAmount(event.amount, currency) : cleanDecimal(event.amount)}`
908
921
  + (event.payDate ? `, payable ${event.payDate}` : ""),
909
922
  })),
910
923
  ...data.splits.map((event) => ({
@@ -1096,13 +1109,15 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
1096
1109
  const quiet = ended ? null : noPrintsTodayText(row.quote, now);
1097
1110
  return [ended ?? (quiet ? `${label}: ${quiet}` : []), quoteBarNotes(label, row.quote, now)].flat();
1098
1111
  }),
1099
- // A receipt and its home line each say the ratio, as `ticker` does.
1112
+ // A receipt and its home line each say the ratio, as `ticker` does; a CEDEAR names itself in its own.
1100
1113
  ...data.flatMap((row) => {
1114
+ const cedear = listingCedearRatio({ quote: row.quote });
1115
+ if (cedear) return [`${cedearRatioText(cedear)}.`];
1101
1116
  const pair = listingDepositaryPair({ quote: row.quote });
1102
1117
  return pair ? [`${row.target.symbol}: ${depositaryPairText(pair, isReceiptSide({ quote: row.quote }))}.`] : [];
1103
1118
  }),
1104
1119
  // A cell shows only "unavailable", and an exported row only its status, so stderr names each failure; the JSON rows carry each reason.
1105
- ...ctx.cliOptions.format !== "json" ? quoteNotes(data, { exchange }) : [],
1120
+ ...ctx.cliOptions.format !== "json" ? quoteNotes(data) : [],
1106
1121
  ];
1107
1122
  const columns = commandName === "compare" ? compareColumns() : quoteColumns();
1108
1123
  const basisNotes = changeBasisNotes(data, now);
@@ -1117,7 +1132,8 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
1117
1132
  // close does not read as a contradiction of DGS10 or GC for the same day.
1118
1133
  // Dated by the quotes as served, which say whether one is the saved copy.
1119
1134
  freshness: withSavedCopy(
1120
- quotesFreshness(data.map((row) => row.quote), yieldsOnly ? { schedule: `Cboe close ${CBOE_YIELD_INDEX_CLOSE}` } : undefined),
1135
+ // A table across markets (US and London lines) dates each market's session and says when each opens.
1136
+ quotesFreshness(data.map((row) => row.quote), { datesEachVenue: true, ...yieldsOnly ? { schedule: `Cboe close ${CBOE_YIELD_INDEX_CLOSE}` } : {} }),
1121
1137
  answers.map(({ result }) => result.quote),
1122
1138
  ),
1123
1139
  }, {
@@ -1399,7 +1415,11 @@ async function loadListingHistory(
1399
1415
  };
1400
1416
  // A coin's volume is traded value in its quote currency: said in every row and on the status line.
1401
1417
  const volume = historyVolume(unit, traded);
1402
- const rows = historyRows(points, resolution, unit.currency, unit.unit, volume);
1418
+ // Spot FX has no exchange to count its trades: a source's 0 is no volume, printed as missing.
1419
+ const pair = quote?.instrumentType === "CURRENCY" || isCurrencyPairListing(symbol, exchange);
1420
+ // A London line's bars were priced in pence: cleaned there, and printed to the pence decimals `quote` shows.
1421
+ const priceDivisor = quotedPriceDivisor(quote);
1422
+ const rows = historyRows(pair ? points.map(({ volume: _volume, ...point }) => point) : points, resolution, unit.currency, unit.unit, volume, priceDivisor);
1403
1423
  // Bars stop arriving on the listing's own trading days, not New York's.
1404
1424
  const venue = quote?.listingExchangeName || exchange || undefined;
1405
1425
  const served = range === "YTD" && !window ? rows.slice(Math.max(0, yearToDateStartIndex(rows.map((row) => row.date), rows[0]?.interval, venue))) : rows;
@@ -1450,7 +1470,7 @@ async function loadListingHistory(
1450
1470
  ].flat();
1451
1471
  return {
1452
1472
  listing, identity, unit, data, resolution, interval, intraday, volume, freshness, notes,
1453
- decimals: historyPriceDecimals(data, listing.saved?.metadata.assetCategory),
1473
+ decimals: historyPriceDecimals(data, listing.saved?.metadata.assetCategory, priceDivisor),
1454
1474
  };
1455
1475
  }
1456
1476
 
@@ -1720,6 +1740,22 @@ const STATEMENT_COLUMNS: CliResultColumn<ReturnType<typeof financialStatementRow
1720
1740
  { key: "currency", header: "Cur" },
1721
1741
  ];
1722
1742
 
1743
+ /** A symbol as typed in capitals (`NEE`, `BP:LSE`, `7203.T`), never a word of a company's name. */
1744
+ const TYPED_SYMBOL = /^[A-Z0-9][A-Z0-9.:^=&-]{0,15}$/;
1745
+
1746
+ /**
1747
+ * The symbols of a command given several where it takes one: `NEE FSLR` as
1748
+ * two words, or as one (`"NEE FSLR"`, `NEE,FSLR`). One word with spaces is
1749
+ * a list only when every part is a symbol as typed, so a company's name
1750
+ * (`"Bank of America"`) is still searched for. Null for one symbol.
1751
+ */
1752
+ export function comparedSymbols(args: readonly string[]): string[] | null {
1753
+ const words = args.flatMap((arg) => arg.split(/[\s,]+/)).filter(Boolean);
1754
+ if (words.length < 2) return null;
1755
+ if (args.length > 1 || args.some((arg) => arg.includes(","))) return words;
1756
+ return words.every((word) => TYPED_SYMBOL.test(word)) ? words : null;
1757
+ }
1758
+
1723
1759
  async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1], view: FinancialsView) {
1724
1760
  const args = [...rawArgs];
1725
1761
  const exchangeOption = takeOption(args, "--exchange");
@@ -1744,6 +1780,12 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
1744
1780
  const tabular = ctx.cliOptions.format === "csv" || ctx.cliOptions.format === "ndjson";
1745
1781
  if (sectionFlag && !tabular) ctx.fail("--section picks one table of --csv or --ndjson output.");
1746
1782
  if (sectionFlag && !section?.trim()) ctx.fail("--section needs a section title or number.");
1783
+ // Several symbols are a comparison, which RV draws side by side.
1784
+ const compared = view === "valuation" ? comparedSymbols(args) : null;
1785
+ if (compared) {
1786
+ ctx.fail(`valuation takes one symbol; got ${compared.join(" ")}.`,
1787
+ `To compare their valuations side by side: gloom fn RV ${compared.join(",")}\nUsage: gloom valuation <symbol>`);
1788
+ }
1747
1789
  const raw = requireOneArg(args, `${commandName} <symbol>`, "symbol", ctx);
1748
1790
  const selectTables = (tables: CliReportTables) => {
1749
1791
  try {
@@ -1765,8 +1807,8 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
1765
1807
  // declared distribution it annualizes (not in JSON), and one whose dividend stopped says so; read beside the listing notes.
1766
1808
  const distributions = view === "statements" ? null : loadDividendDistributions(
1767
1809
  market.dataProvider, listing.request, financials, { declared: ctx.cliOptions.format !== "json" });
1768
- // A bond fund's SEC yield, yield to worst and duration, beside its distribution yield.
1769
- const bondFund = view === "statements" ? null : loadReportBondFacts(listing.request.symbol,
1810
+ // A fund's facts: its bond figures beside its distribution yield, and whether fn ETF has any to point to.
1811
+ const fundFacts = view === "statements" ? null : loadReportFundFacts(listing.request.symbol,
1770
1812
  financials.quote?.tradingExchangeName || listing.request.exchange || financials.quote?.listingExchangeName || financials.quote?.exchangeName,
1771
1813
  financials, listing.saved);
1772
1814
  const treasury = rates ? loadTreasuryTenors() : null;
@@ -1795,13 +1837,14 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
1795
1837
  loadBankFigures(market.statementSources, listing.request, financials),
1796
1838
  ])
1797
1839
  : [null, { bank: null, note: null }];
1798
- const bond = await bondFund;
1840
+ const facts = await fundFacts;
1841
+ const bond = facts?.bond ?? null;
1799
1842
  // On the SEC yield when the sponsor publishes one, else the distribution yield the line above shows.
1800
1843
  const taxEquivalent = rates ? analyzeTaxEquivalent({
1801
1844
  symbol: identity.symbol || listing.key, bond, rates, treasury: await treasury,
1802
1845
  distribution: distributionBasis(priced.fundamentals?.dividendYield, priced.fundamentals?.dividendYieldBasis === "trailing" ? "trailing" : "forward"),
1803
1846
  }) : null;
1804
- const report = { ...data, distributions: await distributions, statementFilings, bank: bank.bank, bankNote: bank.note, bondFund: bond, taxEquivalent,
1847
+ const report = { ...data, distributions: await distributions, statementFilings, bank: bank.bank, bankNote: bank.note, bondFund: bond, fundFacts: facts, taxEquivalent,
1805
1848
  // A base currency other than USD reads every amount with its code, as `ticker` does.
1806
1849
  currencyCodes: writesCurrencyCodes(market.config) };
1807
1850
  ctx.printResult({
@@ -1895,26 +1938,29 @@ const NEWS_COLUMNS = [
1895
1938
  async function printNewsSearch(
1896
1939
  text: string,
1897
1940
  articles: NewsArticle[],
1898
- { reason, empty, commodity = true, failure, ticker = null }: {
1941
+ { reason, empty, commodity = true, failure, ticker = null, closest = false }: {
1899
1942
  reason?: string;
1900
1943
  empty?: string;
1901
1944
  commodity?: boolean;
1902
1945
  failure?: string;
1903
1946
  /** The listing a coin pair's search stands in for. */
1904
1947
  ticker?: string | null;
1948
+ /** No story has every word: these are the ones with the most. */
1949
+ closest?: boolean;
1905
1950
  },
1906
1951
  ctx: Parameters<CliCommandDef["execute"]>[1],
1907
1952
  ) {
1908
1953
  const searched = failure === undefined;
1909
1954
  const named = searched && commodity && articles.length === 0 && commodityNamedIn(text) !== null;
1910
1955
  const route = named ? await commodityNewsRoute(text) : null;
1956
+ const closestReason = closest && articles.length > 0 ? closestStoriesReason(text) : null;
1911
1957
  ctx.printResult({
1912
1958
  data: articles,
1913
1959
  ...(searched ? {} : { warnings: [`Searching stories for "${text}" failed: ${failure}`] }),
1914
- metadata: { ticker, search: text, feed: null, ...(route ? { futuresNews: route.command } : {}) },
1960
+ metadata: { ticker, search: text, feed: null, ...(closestReason ? { match: "closest" } : {}), ...(route ? { futuresNews: route.command } : {}) },
1915
1961
  freshness: rowsFreshness(newsRows(articles), cloudNewsFreshness(await cloudRealtimeAccess())),
1916
1962
  }, {
1917
- heading: newsSearchHeading(text, reason),
1963
+ heading: newsSearchHeading(text, [reason, closestReason].filter(Boolean).join(" · ") || undefined),
1918
1964
  rows: newsRows,
1919
1965
  columns: NEWS_COLUMNS,
1920
1966
  empty: named ? noStoriesMessage(text, route) : empty ?? (searched ? noStoriesMessage(text, null) : "No stories to show."),
@@ -1976,7 +2022,8 @@ async function runNews(rawArgs: string[], ctx: Parameters<CliCommandDef["execute
1976
2022
  if (exchangeOption || feed) ctx.fail(`${exchangeOption ? "--exchange" : "--feed"} goes with a symbol, not with text to search stories for.`, "Usage: gloom news <query>");
1977
2023
  const problem = newsSearchTextProblem(text);
1978
2024
  if (problem) ctx.fail(problem);
1979
- await printNewsSearch(text, await searchNewsStories(text, limit), {}, ctx);
2025
+ const answer = await searchClosestNewsStories(text, limit);
2026
+ await printNewsSearch(text, answer.found, { closest: answer.closest }, ctx);
1980
2027
  return;
1981
2028
  }
1982
2029
  // A metal's future or name is its market's news, not a company's: GOLD in capitals stays Gold.com's.
@@ -2043,7 +2090,8 @@ async function runNews(rawArgs: string[], ctx: Parameters<CliCommandDef["execute
2043
2090
  return;
2044
2091
  }
2045
2092
  const empty = emptyMessage(false);
2046
- const read = listing ? listingReadNotes(listing) : [];
2093
+ // A bare coin ticker read as another listing (ETH, the Grayscale fund) says where the coin is, as `quote` does.
2094
+ const read = listing ? [...listingReadNotes(listing), ...coinListingNotes(listing, quote)] : [];
2047
2095
  // A word that is also the company's name ("gold" for Gold.com Inc.) says once which ticker it found and how
2048
2096
  // to search the stories that mention it instead, when those stories are mostly about something else.
2049
2097
  const typed = args[0]?.trim() ?? "";
@@ -2155,7 +2203,7 @@ async function runFilings(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2155
2203
  ...listingMetadata(resolved), ...(form ? { form } : {}),
2156
2204
  ...(page ? { announcementsPage: page.url } : {}),
2157
2205
  },
2158
- freshness: rowsFreshness(filingRows(filings), { ...SEC_FILINGS, observedKey: "filingDate" }),
2206
+ freshness: rowsFreshness(filingRows(filings), SEC_FILING_ROWS),
2159
2207
  ...(choice.length > 0 ? { warnings: choice } : {}),
2160
2208
  }, {
2161
2209
  heading: listingHeading(resolved),
@@ -2167,7 +2215,7 @@ async function runFilings(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2167
2215
  empty: [form ? `No ${form} filings found for ${listingTitle(resolved)}.`
2168
2216
  : identity ? noSecReportsNotice(resolved)
2169
2217
  : `No SEC filings found for ${listingTitle(resolved)}.`, pageLine].filter(Boolean).join("\n"),
2170
- ...(pageLine ? { footnote: pageLine, exportNotes: [pageLine] } : {}),
2218
+ ...filingsFootnote(pageLine, filings[0]?.companyFrom),
2171
2219
  });
2172
2220
  } catch (error) {
2173
2221
  if (!(error instanceof SecRegistrantMismatchError)) throw error;
@@ -2185,6 +2233,16 @@ async function runFilings(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2185
2233
  });
2186
2234
  }
2187
2235
 
2236
+ /**
2237
+ * The lines `filings` prints under its rows and CSV writes as notes: an ASX
2238
+ * listing's announcements page, and whose filings a foreign line shows when
2239
+ * they are its company's home line's.
2240
+ */
2241
+ function filingsFootnote(pageLine: string | null | undefined, companyFrom: CompanyFrom | undefined): { footnote?: string; exportNotes?: string[] } {
2242
+ const lines = [...(pageLine ? [pageLine] : []), ...companyDataNotes(companyFrom)];
2243
+ return lines.length ? { footnote: lines.join("\n"), exportNotes: lines } : {};
2244
+ }
2245
+
2188
2246
  /**
2189
2247
  * `filings` for a company on ASX that files nothing with the SEC: its latest
2190
2248
  * ASX announcements from Gloom Cloud, newest first, under the line saying it
@@ -2355,7 +2413,8 @@ async function printBeneficialOwners(
2355
2413
  heading: `${listingHeading(identity)}${cliStyles.muted(beneficialListFacts(payload, form, rows.length, history).map((fact) => ` · ${fact}`).join(""))}`,
2356
2414
  // Text draws each column as the HDS report does; CSV and JSON keep the raw values.
2357
2415
  textColumns: BENEFICIAL_REPORT_COLUMNS.map((column) => ({ ...column, format: column.textFormat ?? column.format })),
2358
- ...(legend ? { footnote: legend } : {}),
2416
+ // A foreign line's owners read from its company's home line say whose.
2417
+ ...(legend || payload.companyFrom ? { footnote: [legend, ...companyDataNotes(payload.companyFrom)].filter(Boolean).join("\n") } : {}),
2359
2418
  columns: [
2360
2419
  ...BENEFICIAL_REPORT_COLUMNS.map(({ key, header, align }) => ({ key, header, ...(align ? { align } : {}) })),
2361
2420
  { key: "otherPersons", header: "Other persons" },
@@ -2401,14 +2460,20 @@ async function runHolders(
2401
2460
  // --tail counts back from the end of the rows loaded, so it loads at least as many as it asks for.
2402
2461
  const tail = ctx.cliOptions.tail;
2403
2462
  const indexLimit = Math.min(ctx.cliOptions.limit ?? Math.max(tail ?? 0, HOLDERS_DEFAULT_ROWS), HOLDER_ROWS_MAX);
2463
+ const quoted = loadListingQuote(market.dataProvider, listing);
2404
2464
  const [source, quote, form4, index] = await Promise.all([
2405
2465
  loadForListing(
2406
2466
  listing, market, ctx,
2407
2467
  () => market.dataProvider.getHolders(listing.request.symbol, listing.request.exchange),
2408
2468
  (found) => found.holders.length === 0,
2409
2469
  { command: commandName, noun: "holder data" },
2410
- ),
2411
- loadListingQuote(market.dataProvider, listing),
2470
+ ).catch(async (error: unknown) => {
2471
+ // A fund has no ownership breakdown: say so, and what reads it, rather than the source's NO_DATA.
2472
+ const fund = await fundHoldersAnswer(listing.symbol, error, await quoted, apiClient);
2473
+ if (fund) fail(fund.message, fund.details.join("\n") || undefined, NO_DATA_CODE);
2474
+ throw error;
2475
+ }),
2476
+ quoted,
2412
2477
  insiderCommand ? loadForm4Report(market, listing) : null,
2413
2478
  indexTicker ? loadIndexedHolders(indexTicker, indexLimit).catch(logFailure("cli.commands-market", "Read the 13F holder index failed", null)) : null,
2414
2479
  ]);
@@ -2450,7 +2515,7 @@ async function runHolders(
2450
2515
  const columns = holderReportColumns(shownRows, valueCurrency);
2451
2516
  // Dated as HDS dates it: by the list's as-of; an insider report of Form 4 filings alone as INS dates it, by the newest.
2452
2517
  const freshness = form4Only
2453
- ? rowsFreshness(form4?.newestFiled ? [{ filingDate: form4.newestFiled }] : [], { ...SEC_FILINGS, basis: "Form 4 filings", observedKey: "filingDate" })
2518
+ ? rowsFreshness(form4?.newestFiled ? [{ filingDate: form4.newestFiled }] : [], { ...SEC_FILING_ROWS, basis: "Form 4 filings" })
2454
2519
  : rowsFreshness(shownRows, { ...SEC_FILINGS, basis: "13F filings" }, { asOf: data.asOf ?? null });
2455
2520
  // Named as fn HDS takes it, so the closing notes point to the same listing.
2456
2521
  const requested = exchangeOption && !raw.includes(":") ? `${raw}:${exchangeOption.toUpperCase()}` : raw;
@@ -2520,6 +2585,8 @@ async function runHolders(
2520
2585
  insiderCommand ? insiderSummary(data, listing, identity, form4) : "",
2521
2586
  ].filter(Boolean).join("\n"),
2522
2587
  empty: `No holders reported for ${listingTitle(identity)}.`,
2588
+ // Holders read from the company's home line say whose; the SEC index's are the listing's own.
2589
+ ...(!indexed && data.companyFrom ? { footnote: companyDataNotes(data.companyFrom).join("\n") } : {}),
2523
2590
  });
2524
2591
  });
2525
2592
  }
@@ -2616,12 +2683,13 @@ async function runEvents(rawArgs: string[], ctx: Parameters<CliCommandDef["execu
2616
2683
  async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
2617
2684
  const args = [...rawArgs];
2618
2685
  const leapsOptions = takeLeapsOptions(args);
2619
- const expiration = takeOption(args, "--expiration");
2686
+ const expirationOption = takeExpirationOption(args);
2687
+ const { value: expiration, flag: expirationFlag } = expirationOption;
2688
+ if (expirationOption.both) ctx.fail("--expiry is --expiration; give one of them.", `Usage: gloom ${OPTIONS_USAGE}`);
2620
2689
  const exchangeOption = takeOption(args, "--exchange");
2621
2690
  if (leapsOptions.leaps) {
2622
2691
  // With --leaps, --expiration is a window of one expiry.
2623
- const expirationGiven = expiration != null || rawArgs.some((arg) => arg === "--expiration" || arg.startsWith("--expiration="));
2624
- const criteria = parseLeapsCriteria({ ...leapsOptions.raw, ...expirationGiven ? { "--expiration": expiration ?? "" } : {} });
2692
+ const criteria = parseLeapsCriteria({ ...leapsOptions.raw, ...expirationOption.given ? { "--expiration": expiration ?? "" } : {} });
2625
2693
  if ("error" in criteria) ctx.fail(criteria.error, `Usage: gloom ${LEAPS_USAGE}`);
2626
2694
  const entries = normalizeSymbols(args);
2627
2695
  if (entries.length === 0) ctx.fail("--leaps needs at least one symbol.", `Usage: gloom ${LEAPS_USAGE}`);
@@ -2633,11 +2701,11 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2633
2701
  }
2634
2702
  const raw = requireOneArg(args, OPTIONS_USAGE, "symbol", ctx);
2635
2703
  let expirationDate: number | undefined;
2636
- if (expiration != null || rawArgs.includes("--expiration")) {
2704
+ if (expirationOption.given) {
2637
2705
  const parsed = expiration == null ? null : parseOptionExpiration(expiration);
2638
2706
  if (parsed == null) {
2639
2707
  ctx.fail(
2640
- expiration == null ? "--expiration needs a date." : `Invalid --expiration "${expiration}".`,
2708
+ expiration == null ? `${expirationFlag} needs a date.` : `Invalid ${expirationFlag} "${expiration}".`,
2641
2709
  `Use ${OPTION_EXPIRATION_FORMAT}.${expiration == null ? "" : expirationHint(expiration)}\nUsage: gloom ${OPTIONS_USAGE}`,
2642
2710
  );
2643
2711
  }
@@ -2669,7 +2737,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2669
2737
  const listed = await readChain(undefined).then(({ chain }) => chain.expirationDates,
2670
2738
  logFailure("cli-market", "Read available option expirations failed", []));
2671
2739
  ctx.fail(`expiry ${expiryIsoDate(expirationDate)} for ${listing.key} `
2672
- + expiredExpiryText(expirationDate, listed, now, { exchange: expiryVenue, flag: "expiration" }),
2740
+ + expiredExpiryText(expirationDate, listed, now, { exchange: expiryVenue, flag: expirationFlag.slice(2) }),
2673
2741
  `Run gloom options ${listing.key} to list the live expiries.`);
2674
2742
  }
2675
2743
  const { result, chain: read } = await loadForListing(listing, market, ctx, async () => {
@@ -2711,7 +2779,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2711
2779
  // IV and delta are valued at one spot and instant, named under the table and on every exported row.
2712
2780
  const { chain, spot: modelSpot } = valueChainAtModelSpot(loaded, inputs, Date.now(), identity.exchange);
2713
2781
  const basis: OptionsChainBasis = { spot: modelSpot, dividendYield: inputs.dividendYield ?? null,
2714
- openInterest: await loadOptionsChainOpenInterest(symbol, chain) };
2782
+ openInterest: await loadOptionsChainOpenInterest(symbol, chain), ivFilled: chainHasFilledIv(chain) };
2715
2783
  const basisFields = optionsBasisFields(basis);
2716
2784
  const currency = [...chain.calls, ...chain.puts].find((contract) => contract.currency?.trim())?.currency.trim().toUpperCase()
2717
2785
  ?? quote?.currency ?? null;
@@ -2783,6 +2851,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2783
2851
  { key: "bid", header: "Bid" },
2784
2852
  { key: "ask", header: "Ask" },
2785
2853
  { key: "iv", header: "IV (annualized decimal)" },
2854
+ { key: "ivSource", header: "IV source" },
2786
2855
  { key: "delta", header: "Delta (decimal)" },
2787
2856
  { key: "volume", header: "Vol" },
2788
2857
  { key: "openInterest", header: "OI" },
@@ -2810,7 +2879,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2810
2879
  { key: "coinAsk", header: `Ask ${coin}`, align: "right", format: formatCoinPremiumCell },
2811
2880
  { key: "coinMark", header: `Mark ${coin}`, align: "right", format: formatCoinPremiumCell },
2812
2881
  { key: "mark", header: "Mark $", align: "right", format: formatOptionDollarCell },
2813
- { key: "iv", header: "IV", align: "right", format: formatOptionIvCell },
2882
+ { key: "iv", header: "IV", align: "right", format: (value, row) => formatOptionIvCell(value, row) },
2814
2883
  { key: "delta", header: "Delta", align: "right", format: formatOptionDeltaCell },
2815
2884
  { key: "gamma", header: "Gamma", align: "right", format: formatOptionGammaCell, optional: true, dropPriority: 3 },
2816
2885
  { key: "vega", header: "Vega $", align: "right", format: formatOptionDollarCell, optional: true, dropPriority: 2 },
@@ -2826,7 +2895,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2826
2895
  { key: "last", header: "Last", align: "right" },
2827
2896
  { key: "bid", header: "Bid", align: "right", format: (_value, row) => formatOptionQuoteCell(row, "bid") },
2828
2897
  { key: "ask", header: "Ask", align: "right", format: (_value, row) => formatOptionQuoteCell(row, "ask") },
2829
- { key: "iv", header: "IV", align: "right", format: formatOptionIvCell },
2898
+ { key: "iv", header: "IV", align: "right", format: (value, row) => formatOptionIvCell(value, row) },
2830
2899
  { key: "delta", header: "Delta", align: "right", format: formatOptionDeltaCell },
2831
2900
  { key: "volume", header: "Vol", align: "right", format: formatCountCell, optional: true, dropPriority: 1 },
2832
2901
  { key: "openInterest", header: "OI", align: "right", format: formatCountCell, optional: true, dropPriority: 1 },
@@ -3250,7 +3319,7 @@ export const marketDataCliCommands: BuiltinCliCommandDef[] = [
3250
3319
  usage: [OPTIONS_USAGE, LEAPS_USAGE],
3251
3320
  options: [
3252
3321
  {
3253
- flags: `--expiration <${OPTION_EXPIRATION_PLACEHOLDER}>`,
3322
+ flags: `--expiration <${OPTION_EXPIRATION_PLACEHOLDER}>, --expiry <${OPTION_EXPIRATION_PLACEHOLDER}>`,
3254
3323
  description: "Expiration as a date (2028-01-21) or Unix seconds; defaults to the nearest one, and lists the others. With --leaps: rank that expiry alone",
3255
3324
  },
3256
3325
  EXCHANGE_OPTION,
@@ -82,6 +82,28 @@ export async function searchNewsStories(text: string, limit: number, topics?: re
82
82
  return response.items.map((item) => mapCloudNewsArticle(item));
83
83
  }
84
84
 
85
+ /** A search's stories, and whether they are its closest ones because no story has every word. */
86
+ export interface NewsSearchAnswer {
87
+ found: NewsArticle[];
88
+ closest: boolean;
89
+ }
90
+
91
+ /**
92
+ * The stories matching the text; when no story has every word of a search of
93
+ * several, the ones with the most of them, most words first. Spellings of
94
+ * one word are one word to the service: lockup, lock-up and lock up;
95
+ * spinoff and spin-off; expiry and expiration.
96
+ */
97
+ export async function searchClosestNewsStories(text: string, limit: number): Promise<NewsSearchAnswer> {
98
+ const response = await apiClient.searchCloudNews(text, limit, undefined, { closest: true });
99
+ return { found: response.items.map((item) => mapCloudNewsArticle(item)), closest: response.match === "closest" };
100
+ }
101
+
102
+ /** What the heading says of a search no story has every word of. */
103
+ export function closestStoriesReason(text: string): string {
104
+ return `no story has every word of "${text}"; the closest, most words first`;
105
+ }
106
+
85
107
  /** The NI code of the metal markets: prices, futures, bullion and the trusts that hold it, not a miner's releases. */
86
108
  export const METALS_NEWS_TOPIC = "metals";
87
109