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
@@ -12,7 +12,7 @@ import type {
12
12
  Quote,
13
13
  TickerFinancials,
14
14
  } from "../../types/financials";
15
- import { currencyPriceMinDigits, formatMarketPrice, formatMarketPriceWithCurrency, quoteFormatOptions, resolveAssetDisplayKind, withCurrencyMinorDigits } from "../../market-data/market/format";
15
+ import { currencyPriceMinDigits, formatMarketPrice, formatMarketPriceWithCurrency, penceFigure, quoteFormatOptions, resolveAssetDisplayKind, withCurrencyMinorDigits } from "../../market-data/market/format";
16
16
  import { INDEX_POINTS_EXPORT_UNIT, isIndexLevel, reportedQuoteVolume } from "../../market-data/market/index-level";
17
17
  import { changeBasisJson, changeBasisLabel, changeBasisNote, quoteChangeBasis, quotePreviousCloseDate, quoteSettleText } from "../../market-data/market/change-basis";
18
18
  import {
@@ -41,6 +41,7 @@ import {
41
41
  import { cliArrow, cliStyles, colorBySign, renderSection, renderStats } from "../../utils/cli-output";
42
42
  import { filledPeriodsNote, stalePeriodNote, statementHistoryNotes } from "../../utils/financial-statements";
43
43
  import { formatPerShareNumber } from "../../utils/reported-money";
44
+ import { isCurrencyPairListing } from "../../utils/fx-market-hours";
44
45
  import {
45
46
  analystTargetCurrency,
46
47
  formatAnalystPrice,
@@ -53,10 +54,12 @@ import {
53
54
  } from "../../plugins/builtin/research/analyst-model";
54
55
  import { getPublishedUsEquityCalendarYears, getPublishedUsEquitySession } from "../../market-data/published-us-sessions";
55
56
  import { isQuoteStaleForCurrentSession, noPrintsTodayText } from "../../market-data/quotes/freshness";
56
- import { isOptionsUnavailableError, listedOptionsAlternative, optionsUnavailableTitle } from "../../market-data/options-alternatives";
57
+ import {
58
+ coinOptionsAlternativesText, isCoinWithoutOptions, isOptionsUnavailableError, listedOptionsAlternative, optionsUnavailableTitle,
59
+ } from "../../market-data/options-alternatives";
57
60
  import {
58
61
  atReportTtmRate, cliFuturesContract, futuresContractMetrics, exportedDividendFundamentals, fundamentalsReportTables, loadDividendDistributions,
59
- loadReportBondFacts, renderFundamentalsReport, writesCurrencyCodes,
62
+ loadReportFundFacts, renderFundamentalsReport, writesCurrencyCodes,
60
63
  } from "./ticker";
61
64
  import { createBaseConverter } from "../base-converter";
62
65
  import { loadStatementFilings } from "../statement-filings";
@@ -72,9 +75,16 @@ import {
72
75
  formatExpiryList,
73
76
  loadOptionModelInputs,
74
77
  loadOptionsChainOpenInterest,
78
+ chainCoinCurrency,
79
+ chainHasFilledIv,
80
+ formatCoinPremiumCell,
75
81
  formatOptionDeltaCell,
82
+ formatOptionDollarCell,
83
+ formatOptionGammaCell,
76
84
  formatOptionIvCell,
77
85
  formatOptionQuoteCell,
86
+ isMarkedChain,
87
+ MARKED_OPTION_FIELDS,
78
88
  OPTION_MODEL_RATE,
79
89
  OPTION_VOLATILITY_FIELDS,
80
90
  OPTIONS_USAGE,
@@ -82,12 +92,13 @@ import {
82
92
  optionsBasisFields,
83
93
  optionsBasisFootnote,
84
94
  parseOptionExpiration,
95
+ takeExpirationOption,
85
96
  valueChainAtModelSpot,
86
97
  type OptionsChainBasis,
87
98
  } from "./options-chain";
88
99
  import {
89
100
  expirationHint, expiredExpiryText, expiryIsoDate, isLiveOptionExpiry, liveDefaultExpiry, liveOptionExpiries, missingExpiryMessage,
90
- OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER, withLiveExpiryList,
101
+ OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER, optionExpiryVenue, withLiveExpiryList,
91
102
  } from "../../utils/option-expiry";
92
103
  import { DATE_OPTION_EXAMPLES, isoDateOption, isoDateToday } from "../../utils/calendar-date";
93
104
  import { apiClient } from "../../api-client";
@@ -115,6 +126,7 @@ import {
115
126
  closedPeriodBarDay,
116
127
  formingPeriodBar,
117
128
  historyBarStatusNote,
129
+ venueTradingDay,
118
130
  historyCoverageWarning,
119
131
  historyFacts,
120
132
  historyFlagNote,
@@ -130,6 +142,7 @@ import {
130
142
  historyPriceDecimals,
131
143
  historyRows,
132
144
  historyUnit,
145
+ quotedPriceDivisor,
133
146
  historyVolume,
134
147
  historyVolumeText,
135
148
  type HistoryRow,
@@ -144,7 +157,7 @@ import {
144
157
  symbolListNotes,
145
158
  type HistoryListRow,
146
159
  } from "../history-export";
147
- import { isCliFailure } from "../errors";
160
+ import { fail, isCliFailure, NO_DATA_CODE } from "../errors";
148
161
  import { mapWithConcurrency } from "../../utils/concurrency";
149
162
  import { MISSING_VOLUME_TEXT } from "../../utils/price-history-integrity";
150
163
  import { CRYPTO_BOARD_HINT, quoteNotes } from "./crypto-hints";
@@ -206,6 +219,7 @@ import {
206
219
  type ResolvedEarningsEvent,
207
220
  } from "../../plugins/builtin/shared/earnings-calendar";
208
221
  import {
222
+ coinListingNotes,
209
223
  EXCHANGE_OPTION,
210
224
  listingHeading,
211
225
  listingIdentity,
@@ -294,6 +308,7 @@ import {
294
308
  unvaluedHoldersNote,
295
309
  } from "../../plugins/builtin/holders/report-rows";
296
310
  import { fetchBeneficialOwners } from "../../plugins/builtin/holders/beneficial-client";
311
+ import { fundHoldersAnswer } from "../../plugins/builtin/holders/fund-holders";
297
312
  import { centralBankEventsMessage } from "../central-bank-events";
298
313
  import { classSharesAsOf, classSharesToday } from "../../plugins/builtin/holders/client";
299
314
  import {
@@ -456,7 +471,8 @@ const QUOTE_LEAD_COLUMNS = [
456
471
  row.error && !row.price
457
472
  // A typo is not an outage: say what is wrong with the symbol itself.
458
473
  ? isNotATickerMessage(row.error) ? cliStyles.warning("not a ticker") : cliStyles.danger("unavailable")
459
- : yieldLevelCell(row.price, row)
474
+ // 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.
475
+ : `${yieldLevelCell(row.price, row)}${row.pence ? ` ${cliStyles.muted(row.pence)}` : ""}`
460
476
  ),
461
477
  },
462
478
  {
@@ -683,7 +699,7 @@ function changeBasisNotes(results: QuoteCliRecord[], now = Date.now()): string[]
683
699
  function withPreviousCloseDate(quote: Quote | null | undefined): (Quote & { previousCloseDate?: string | null }) | null {
684
700
  if (!quote) return null;
685
701
  const previousCloseDate = quotePreviousCloseDate(quote);
686
- const entries = Object.entries(quote);
702
+ const entries = Object.entries(quote).filter(([key]) => key !== "previousCloseDate");
687
703
  const at = entries.findIndex(([key]) => key === "previousClose");
688
704
  entries.splice(at < 0 ? entries.length : at + 1, 0, ["previousCloseDate", previousCloseDate]);
689
705
  return Object.fromEntries(entries) as Quote & { previousCloseDate?: string | null };
@@ -720,10 +736,12 @@ function quoteRows(results: QuoteCliRecord[], now = Date.now()) {
720
736
  // A price in cents says what it is per, as the contract terms word it: 314.95¢/lb.
721
737
  const per = display.price != null ? futuresPricePer(result.futuresContract, quote?.currency) : "";
722
738
  const previousClose = display.price != null && display.change != null ? display.price - display.change : quote?.previousClose;
739
+ const last = price(display.price);
723
740
  return {
724
741
  symbol: result.target.symbol,
725
742
  name: quote?.name || result.listing?.name || "",
726
- price: `${price(display.price)}${per}`,
743
+ price: `${last}${per}`,
744
+ pence: penceFigure(display.price, quote, /\.(\d+)/.exec(last)?.[1]?.length ?? 0),
727
745
  rawPrice: display.price,
728
746
  priceBasis: quote?.priceBasis ?? null,
729
747
  instrumentType: quote?.instrumentType ?? null,
@@ -1007,13 +1025,14 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
1007
1025
  : listings.map((listing) => [listing, startTickerChangeLookup(market.dataProvider, listing.symbol, listing.exchange)] as const));
1008
1026
  // The service's quote of the moment, not each form's local copy from whenever it was last asked for:
1009
1027
  // BRK.B saved on NYSE, BRK-B and BRK.B:NYSE print one quote. A local copy answers only offline.
1010
- const results = await market.dataProvider.getQuotesBatch(targets, { forceRefresh: ctx.cliOptions.refresh, revalidate: true });
1028
+ // Each row prints what its move is from (Chg Basis).
1029
+ const results = await market.dataProvider.getQuotesBatch(targets, { forceRefresh: ctx.cliOptions.refresh, revalidate: true, datesChangeBasis: true });
1011
1030
  const listingOf = (result: QuoteBatchResult, index: number) => listings[targets.indexOf(result.target)] ?? listings[index]!;
1012
1031
  const asked = results.map(listingOf);
1013
1032
  const request = { command: commandName, noun: "quote" };
1014
1033
  const answers = await Promise.all(results.map((result, index) => {
1015
1034
  const listing = asked[index]!;
1016
- return answerQuote(result, listing, market, request, ctx.cliOptions.refresh, venues.get(listing) ?? null);
1035
+ return answerQuote(result, listing, market, request, ctx.cliOptions.refresh, venues.get(listing) ?? null, { datesChangeBasis: true });
1017
1036
  }));
1018
1037
  const now = Date.now();
1019
1038
  const symbolChanges = await Promise.all(answers.map(async ({ result }, index) => {
@@ -1092,7 +1111,7 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
1092
1111
  return pair ? [`${row.target.symbol}: ${depositaryPairText(pair, isReceiptSide({ quote: row.quote }))}.`] : [];
1093
1112
  }),
1094
1113
  // A cell shows only "unavailable", and an exported row only its status, so stderr names each failure; the JSON rows carry each reason.
1095
- ...ctx.cliOptions.format !== "json" ? quoteNotes(data, { exchange }) : [],
1114
+ ...ctx.cliOptions.format !== "json" ? quoteNotes(data) : [],
1096
1115
  ];
1097
1116
  const columns = commandName === "compare" ? compareColumns() : quoteColumns();
1098
1117
  const basisNotes = changeBasisNotes(data, now);
@@ -1107,7 +1126,8 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
1107
1126
  // close does not read as a contradiction of DGS10 or GC for the same day.
1108
1127
  // Dated by the quotes as served, which say whether one is the saved copy.
1109
1128
  freshness: withSavedCopy(
1110
- quotesFreshness(data.map((row) => row.quote), yieldsOnly ? { schedule: `Cboe close ${CBOE_YIELD_INDEX_CLOSE}` } : undefined),
1129
+ // A table across markets (US and London lines) dates each market's session and says when each opens.
1130
+ quotesFreshness(data.map((row) => row.quote), { datesEachVenue: true, ...yieldsOnly ? { schedule: `Cboe close ${CBOE_YIELD_INDEX_CLOSE}` } : {} }),
1111
1131
  answers.map(({ result }) => result.quote),
1112
1132
  ),
1113
1133
  }, {
@@ -1389,7 +1409,11 @@ async function loadListingHistory(
1389
1409
  };
1390
1410
  // A coin's volume is traded value in its quote currency: said in every row and on the status line.
1391
1411
  const volume = historyVolume(unit, traded);
1392
- const rows = historyRows(points, resolution, unit.currency, unit.unit, volume);
1412
+ // Spot FX has no exchange to count its trades: a source's 0 is no volume, printed as missing.
1413
+ const pair = quote?.instrumentType === "CURRENCY" || isCurrencyPairListing(symbol, exchange);
1414
+ // A London line's bars were priced in pence: cleaned there, and printed to the pence decimals `quote` shows.
1415
+ const priceDivisor = quotedPriceDivisor(quote);
1416
+ const rows = historyRows(pair ? points.map(({ volume: _volume, ...point }) => point) : points, resolution, unit.currency, unit.unit, volume, priceDivisor);
1393
1417
  // Bars stop arriving on the listing's own trading days, not New York's.
1394
1418
  const venue = quote?.listingExchangeName || exchange || undefined;
1395
1419
  const served = range === "YTD" && !window ? rows.slice(Math.max(0, yearToDateStartIndex(rows.map((row) => row.date), rows[0]?.interval, venue))) : rows;
@@ -1436,11 +1460,11 @@ async function loadListingHistory(
1436
1460
  // The status line says how far a bar still forming runs; the note is for the bars it does not name.
1437
1461
  gaps ?? [], historyJumpNote(data) ?? [], historyFlagNote(data) ?? [], historyMissingVolumeNote(data) ?? [],
1438
1462
  historyVenueVolumeNote(data) ?? [],
1439
- historyBarStatusNote(forming ? served : data) ?? [],
1463
+ historyBarStatusNote(forming ? served : data, { tradingDay: venueTradingDay(venue, Date.now()) }) ?? [],
1440
1464
  ].flat();
1441
1465
  return {
1442
1466
  listing, identity, unit, data, resolution, interval, intraday, volume, freshness, notes,
1443
- decimals: historyPriceDecimals(data, listing.saved?.metadata.assetCategory),
1467
+ decimals: historyPriceDecimals(data, listing.saved?.metadata.assetCategory, priceDivisor),
1444
1468
  };
1445
1469
  }
1446
1470
 
@@ -1641,7 +1665,7 @@ async function runHistoryList(
1641
1665
  oldest: null,
1642
1666
  });
1643
1667
  // A saved copy is marked on the bars a symbol loaded, not on the rows drawn from them (loadListingHistory
1644
- // reads it there): the list ends "couldn't refresh; saved <time>" for the oldest copy among its symbols.
1668
+ // reads it there): the list ends "couldn't refresh; saved copy from <time>" for the oldest copy among its symbols.
1645
1669
  const savedAt = served.flatMap((history) => history.freshness?.savedAt ?? []).sort()[0];
1646
1670
  const freshness = listFreshness && savedAt && !listFreshness.savedAt ? { ...listFreshness, savedAt } : listFreshness;
1647
1671
  const decimals = (row: Record<string, unknown>) => bySymbol.get(String(row.symbol))?.decimals ?? 2;
@@ -1710,6 +1734,22 @@ const STATEMENT_COLUMNS: CliResultColumn<ReturnType<typeof financialStatementRow
1710
1734
  { key: "currency", header: "Cur" },
1711
1735
  ];
1712
1736
 
1737
+ /** A symbol as typed in capitals (`NEE`, `BP:LSE`, `7203.T`), never a word of a company's name. */
1738
+ const TYPED_SYMBOL = /^[A-Z0-9][A-Z0-9.:^=&-]{0,15}$/;
1739
+
1740
+ /**
1741
+ * The symbols of a command given several where it takes one: `NEE FSLR` as
1742
+ * two words, or as one (`"NEE FSLR"`, `NEE,FSLR`). One word with spaces is
1743
+ * a list only when every part is a symbol as typed, so a company's name
1744
+ * (`"Bank of America"`) is still searched for. Null for one symbol.
1745
+ */
1746
+ export function comparedSymbols(args: readonly string[]): string[] | null {
1747
+ const words = args.flatMap((arg) => arg.split(/[\s,]+/)).filter(Boolean);
1748
+ if (words.length < 2) return null;
1749
+ if (args.length > 1 || args.some((arg) => arg.includes(","))) return words;
1750
+ return words.every((word) => TYPED_SYMBOL.test(word)) ? words : null;
1751
+ }
1752
+
1713
1753
  async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1], view: FinancialsView) {
1714
1754
  const args = [...rawArgs];
1715
1755
  const exchangeOption = takeOption(args, "--exchange");
@@ -1734,6 +1774,12 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
1734
1774
  const tabular = ctx.cliOptions.format === "csv" || ctx.cliOptions.format === "ndjson";
1735
1775
  if (sectionFlag && !tabular) ctx.fail("--section picks one table of --csv or --ndjson output.");
1736
1776
  if (sectionFlag && !section?.trim()) ctx.fail("--section needs a section title or number.");
1777
+ // Several symbols are a comparison, which RV draws side by side.
1778
+ const compared = view === "valuation" ? comparedSymbols(args) : null;
1779
+ if (compared) {
1780
+ ctx.fail(`valuation takes one symbol; got ${compared.join(" ")}.`,
1781
+ `To compare their valuations side by side: gloom fn RV ${compared.join(",")}\nUsage: gloom valuation <symbol>`);
1782
+ }
1737
1783
  const raw = requireOneArg(args, `${commandName} <symbol>`, "symbol", ctx);
1738
1784
  const selectTables = (tables: CliReportTables) => {
1739
1785
  try {
@@ -1755,8 +1801,8 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
1755
1801
  // declared distribution it annualizes (not in JSON), and one whose dividend stopped says so; read beside the listing notes.
1756
1802
  const distributions = view === "statements" ? null : loadDividendDistributions(
1757
1803
  market.dataProvider, listing.request, financials, { declared: ctx.cliOptions.format !== "json" });
1758
- // A bond fund's SEC yield, yield to worst and duration, beside its distribution yield.
1759
- const bondFund = view === "statements" ? null : loadReportBondFacts(listing.request.symbol,
1804
+ // A fund's facts: its bond figures beside its distribution yield, and whether fn ETF has any to point to.
1805
+ const fundFacts = view === "statements" ? null : loadReportFundFacts(listing.request.symbol,
1760
1806
  financials.quote?.tradingExchangeName || listing.request.exchange || financials.quote?.listingExchangeName || financials.quote?.exchangeName,
1761
1807
  financials, listing.saved);
1762
1808
  const treasury = rates ? loadTreasuryTenors() : null;
@@ -1785,13 +1831,14 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
1785
1831
  loadBankFigures(market.statementSources, listing.request, financials),
1786
1832
  ])
1787
1833
  : [null, { bank: null, note: null }];
1788
- const bond = await bondFund;
1834
+ const facts = await fundFacts;
1835
+ const bond = facts?.bond ?? null;
1789
1836
  // On the SEC yield when the sponsor publishes one, else the distribution yield the line above shows.
1790
1837
  const taxEquivalent = rates ? analyzeTaxEquivalent({
1791
1838
  symbol: identity.symbol || listing.key, bond, rates, treasury: await treasury,
1792
1839
  distribution: distributionBasis(priced.fundamentals?.dividendYield, priced.fundamentals?.dividendYieldBasis === "trailing" ? "trailing" : "forward"),
1793
1840
  }) : null;
1794
- const report = { ...data, distributions: await distributions, statementFilings, bank: bank.bank, bankNote: bank.note, bondFund: bond, taxEquivalent,
1841
+ const report = { ...data, distributions: await distributions, statementFilings, bank: bank.bank, bankNote: bank.note, bondFund: bond, fundFacts: facts, taxEquivalent,
1795
1842
  // A base currency other than USD reads every amount with its code, as `ticker` does.
1796
1843
  currencyCodes: writesCurrencyCodes(market.config) };
1797
1844
  ctx.printResult({
@@ -2033,7 +2080,8 @@ async function runNews(rawArgs: string[], ctx: Parameters<CliCommandDef["execute
2033
2080
  return;
2034
2081
  }
2035
2082
  const empty = emptyMessage(false);
2036
- const read = listing ? listingReadNotes(listing) : [];
2083
+ // A bare coin ticker read as another listing (ETH, the Grayscale fund) says where the coin is, as `quote` does.
2084
+ const read = listing ? [...listingReadNotes(listing), ...coinListingNotes(listing, quote)] : [];
2037
2085
  // A word that is also the company's name ("gold" for Gold.com Inc.) says once which ticker it found and how
2038
2086
  // to search the stories that mention it instead, when those stories are mostly about something else.
2039
2087
  const typed = args[0]?.trim() ?? "";
@@ -2391,14 +2439,20 @@ async function runHolders(
2391
2439
  // --tail counts back from the end of the rows loaded, so it loads at least as many as it asks for.
2392
2440
  const tail = ctx.cliOptions.tail;
2393
2441
  const indexLimit = Math.min(ctx.cliOptions.limit ?? Math.max(tail ?? 0, HOLDERS_DEFAULT_ROWS), HOLDER_ROWS_MAX);
2442
+ const quoted = loadListingQuote(market.dataProvider, listing);
2394
2443
  const [source, quote, form4, index] = await Promise.all([
2395
2444
  loadForListing(
2396
2445
  listing, market, ctx,
2397
2446
  () => market.dataProvider.getHolders(listing.request.symbol, listing.request.exchange),
2398
2447
  (found) => found.holders.length === 0,
2399
2448
  { command: commandName, noun: "holder data" },
2400
- ),
2401
- loadListingQuote(market.dataProvider, listing),
2449
+ ).catch(async (error: unknown) => {
2450
+ // A fund has no ownership breakdown: say so, and what reads it, rather than the source's NO_DATA.
2451
+ const fund = await fundHoldersAnswer(listing.symbol, error, await quoted, apiClient);
2452
+ if (fund) fail(fund.message, fund.details.join("\n") || undefined, NO_DATA_CODE);
2453
+ throw error;
2454
+ }),
2455
+ quoted,
2402
2456
  insiderCommand ? loadForm4Report(market, listing) : null,
2403
2457
  indexTicker ? loadIndexedHolders(indexTicker, indexLimit).catch(logFailure("cli.commands-market", "Read the 13F holder index failed", null)) : null,
2404
2458
  ]);
@@ -2606,12 +2660,13 @@ async function runEvents(rawArgs: string[], ctx: Parameters<CliCommandDef["execu
2606
2660
  async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
2607
2661
  const args = [...rawArgs];
2608
2662
  const leapsOptions = takeLeapsOptions(args);
2609
- const expiration = takeOption(args, "--expiration");
2663
+ const expirationOption = takeExpirationOption(args);
2664
+ const { value: expiration, flag: expirationFlag } = expirationOption;
2665
+ if (expirationOption.both) ctx.fail("--expiry is --expiration; give one of them.", `Usage: gloom ${OPTIONS_USAGE}`);
2610
2666
  const exchangeOption = takeOption(args, "--exchange");
2611
2667
  if (leapsOptions.leaps) {
2612
2668
  // With --leaps, --expiration is a window of one expiry.
2613
- const expirationGiven = expiration != null || rawArgs.some((arg) => arg === "--expiration" || arg.startsWith("--expiration="));
2614
- const criteria = parseLeapsCriteria({ ...leapsOptions.raw, ...expirationGiven ? { "--expiration": expiration ?? "" } : {} });
2669
+ const criteria = parseLeapsCriteria({ ...leapsOptions.raw, ...expirationOption.given ? { "--expiration": expiration ?? "" } : {} });
2615
2670
  if ("error" in criteria) ctx.fail(criteria.error, `Usage: gloom ${LEAPS_USAGE}`);
2616
2671
  const entries = normalizeSymbols(args);
2617
2672
  if (entries.length === 0) ctx.fail("--leaps needs at least one symbol.", `Usage: gloom ${LEAPS_USAGE}`);
@@ -2623,11 +2678,11 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2623
2678
  }
2624
2679
  const raw = requireOneArg(args, OPTIONS_USAGE, "symbol", ctx);
2625
2680
  let expirationDate: number | undefined;
2626
- if (expiration != null || rawArgs.includes("--expiration")) {
2681
+ if (expirationOption.given) {
2627
2682
  const parsed = expiration == null ? null : parseOptionExpiration(expiration);
2628
2683
  if (parsed == null) {
2629
2684
  ctx.fail(
2630
- expiration == null ? "--expiration needs a date." : `Invalid --expiration "${expiration}".`,
2685
+ expiration == null ? `${expirationFlag} needs a date.` : `Invalid ${expirationFlag} "${expiration}".`,
2631
2686
  `Use ${OPTION_EXPIRATION_FORMAT}.${expiration == null ? "" : expirationHint(expiration)}\nUsage: gloom ${OPTIONS_USAGE}`,
2632
2687
  );
2633
2688
  }
@@ -2642,6 +2697,8 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2642
2697
  const fate = listingFateLoader(listing, market, quotePromise);
2643
2698
  const inputsPromise = loadOptionModelInputs(market.dataProvider, listing, quotePromise, refresh);
2644
2699
  const now = Date.now();
2700
+ // Expiries close on the listing's clock: a coin's options (Deribit) settle at 08:00 UTC on any day.
2701
+ const expiryVenue = optionExpiryVenue(symbol, exchange);
2645
2702
  const readChain = async (expiry: number | undefined) => {
2646
2703
  const cached = await market.dataProvider.getCachedQuery?.("getOptionsChain", [symbol, exchange, expiry, undefined])
2647
2704
  .load({ force: refresh });
@@ -2653,17 +2710,17 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2653
2710
  };
2654
2711
  };
2655
2712
  // An expiry whose last session has closed has no chain to show: it says so, and names the nearest live one.
2656
- if (expirationDate != null && !isLiveOptionExpiry(expirationDate, now, exchange)) {
2713
+ if (expirationDate != null && !isLiveOptionExpiry(expirationDate, now, expiryVenue)) {
2657
2714
  const listed = await readChain(undefined).then(({ chain }) => chain.expirationDates,
2658
2715
  logFailure("cli-market", "Read available option expirations failed", []));
2659
2716
  ctx.fail(`expiry ${expiryIsoDate(expirationDate)} for ${listing.key} `
2660
- + expiredExpiryText(expirationDate, listed, now, { exchange, flag: "expiration" }),
2717
+ + expiredExpiryText(expirationDate, listed, now, { exchange: expiryVenue, flag: expirationFlag.slice(2) }),
2661
2718
  `Run gloom options ${listing.key} to list the live expiries.`);
2662
2719
  }
2663
2720
  const { result, chain: read } = await loadForListing(listing, market, ctx, async () => {
2664
2721
  const first = await readChain(expirationDate);
2665
2722
  // A source can still default to the expiry that lapsed at Friday's close; the nearest live one is shown instead.
2666
- const live = expirationDate == null ? liveDefaultExpiry(first.chain, now, exchange) : undefined;
2723
+ const live = expirationDate == null ? liveDefaultExpiry(first.chain, now, expiryVenue) : undefined;
2667
2724
  if (live === null) return { ...first, chain: { ...first.chain, calls: [], puts: [] } };
2668
2725
  if (live == null) return first;
2669
2726
  // The default's list stays the catalogue: a dated chain can list fewer expiries.
@@ -2672,6 +2729,8 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2672
2729
  expirationDates: [...new Set([...first.chain.expirationDates, ...shown.chain.expirationDates])].sort((a, b) => a - b) } };
2673
2730
  }, undefined, { command: "options", noun: "options chain", fate }).catch((error: unknown) => {
2674
2731
  if (!isOptionsUnavailableError(error)) throw error;
2732
+ // A coin other than BTC and ETH: say which coins have options, and the bitcoin-linked listings.
2733
+ if (isCoinWithoutOptions(listing.key)) return ctx.fail(optionsUnavailableTitle(listing.key), coinOptionsAlternativesText("options"));
2675
2734
  // A future or commodity with no chain of its own: name the listed fund whose options stand in.
2676
2735
  const alternative = listedOptionsAlternative(listing.key);
2677
2736
  // A name read as a fund or an index asks about the company's stock it means, whose options are listed.
@@ -2681,13 +2740,13 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2681
2740
  + ` Strategy payoffs: gloom fn OSA ${alternative.symbol}`
2682
2741
  : "Strategy payoffs on a listed underlying: gloom fn OSA <ticker>");
2683
2742
  });
2684
- const loaded = withLiveExpiryList(read, now, exchange);
2743
+ const loaded = withLiveExpiryList(read, now, expiryVenue);
2685
2744
  const inputs = await inputsPromise;
2686
2745
  if (expirationDate != null && !chainHasExpiry(loaded, expirationDate)) {
2687
2746
  // An unlisted date comes back as an empty chain; its own list of expiries, else the default chain's, says what to pick.
2688
2747
  const listed = loaded.expirationDates.length > 0 ? loaded.expirationDates : await market.dataProvider
2689
2748
  .getOptionsChain(symbol, exchange, undefined, { cacheMode: "default" })
2690
- .then((fallback) => liveOptionExpiries(fallback.expirationDates, now, exchange),
2749
+ .then((fallback) => liveOptionExpiries(fallback.expirationDates, now, expiryVenue),
2691
2750
  logFailure("cli-market", "Read available option expirations failed", []));
2692
2751
  const miss = missingExpiryMessage(listing.key, expirationDate, listed);
2693
2752
  ctx.fail(miss.message, miss.details);
@@ -2697,7 +2756,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2697
2756
  // IV and delta are valued at one spot and instant, named under the table and on every exported row.
2698
2757
  const { chain, spot: modelSpot } = valueChainAtModelSpot(loaded, inputs, Date.now(), identity.exchange);
2699
2758
  const basis: OptionsChainBasis = { spot: modelSpot, dividendYield: inputs.dividendYield ?? null,
2700
- openInterest: await loadOptionsChainOpenInterest(symbol, chain) };
2759
+ openInterest: await loadOptionsChainOpenInterest(symbol, chain), ivFilled: chainHasFilledIv(chain) };
2701
2760
  const basisFields = optionsBasisFields(basis);
2702
2761
  const currency = [...chain.calls, ...chain.puts].find((contract) => contract.currency?.trim())?.currency.trim().toUpperCase()
2703
2762
  ?? quote?.currency ?? null;
@@ -2706,7 +2765,10 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2706
2765
  : `Options refresh failed; showing the chain stored ${new Date(result.fetchedAt).toISOString()}`
2707
2766
  + (chain.asOf ? ` (last trade ${chain.asOf})` : "");
2708
2767
  const sessionWarning = refreshWarning ? null : priorSessionChainWarning(chain, identity.exchange, Date.now());
2709
- const modelWarning = inputs.spot == null && (chain.calls.length > 0 || chain.puts.length > 0)
2768
+ // A venue that marks its contracts (Deribit) states IV and greeks without a quote.
2769
+ const marked = isMarkedChain(chain);
2770
+ const coin = chainCoinCurrency(chain);
2771
+ const modelWarning = !marked && inputs.spot == null && (chain.calls.length > 0 || chain.puts.length > 0)
2710
2772
  ? `IV and delta need a current ${listing.key} quote; those columns are blank`
2711
2773
  : null;
2712
2774
  const listed = chain.expirationDates.length > 0 || chain.calls.length > 0 || chain.puts.length > 0;
@@ -2733,25 +2795,28 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2733
2795
  // `iv` is annualised volatility and `delta` the option's change per 1.00 move in the underlying, both decimals.
2734
2796
  units: { iv: "annualized decimal", delta: "decimal per 1.00 move in the underlying" },
2735
2797
  // What each contract's `iv` and `impliedVolatility` are, so neither is read as the other.
2736
- fields: OPTION_VOLATILITY_FIELDS,
2798
+ fields: marked ? MARKED_OPTION_FIELDS : OPTION_VOLATILITY_FIELDS,
2737
2799
  // What `iv` and `delta` on each contract are valued from; the provider's own impliedVolatility is left as sent.
2738
- model: {
2739
- spot: basisFields.spot, spotBasis: basisFields.spotBasis, spotAsOf: basisFields.spotAsOf,
2740
- valuationTime: modelSpot ? new Date(modelSpot.valuationTime).toISOString() : null,
2741
- dividendYield: inputs.dividendYield ?? null, rate: OPTION_MODEL_RATE,
2742
- },
2800
+ model: marked
2801
+ ? { venue: chain.venue ?? null, marks: "venue", rate: chain.rate ?? 0, basis: "the expiry's forward", coin }
2802
+ : {
2803
+ spot: basisFields.spot, spotBasis: basisFields.spotBasis, spotAsOf: basisFields.spotAsOf,
2804
+ valuationTime: modelSpot ? new Date(modelSpot.valuationTime).toISOString() : null,
2805
+ dividendYield: inputs.dividendYield ?? null, rate: OPTION_MODEL_RATE,
2806
+ },
2743
2807
  openInterest: { asOf: basisFields.openInterestAsOf, listedAsOf: basis.openInterest?.listedDate ?? null,
2744
2808
  compared: basis.openInterest?.compared ?? 0, matched: basis.openInterest?.matched ?? 0 },
2745
2809
  },
2746
2810
  ...(warnings.length > 0 ? { warnings } : {}),
2747
2811
  freshness,
2748
2812
  }, {
2749
- heading: listingHeading(identity),
2813
+ // Options a venue other than the US exchanges lists (Deribit's) are headed by that venue, not the coin's board.
2814
+ heading: chain.venue ? `${cliStyles.bold(identity.name || identity.symbol)}${cliStyles.muted(` · ${chain.venue}`)}` : listingHeading(identity),
2750
2815
  rows: (data: OptionsChain) => optionRows(data).map((row) => ({ ...row, ...basisFields })),
2751
2816
  // Choosing an expiry needs the list; once one is chosen the table is that expiry.
2752
2817
  summary: (data: OptionsChain) => expirationDate == null ? formatExpiryList(data.expirationDates) : "",
2753
2818
  empty: `No option contracts for ${listingTitle(identity)}.`,
2754
- ...(contractCount > 0 ? { footnote: optionsBasisFootnote(basis) } : {}),
2819
+ ...(contractCount > 0 ? { footnote: optionsBasisFootnote(basis, chain) } : {}),
2755
2820
  exportIdentity: { symbolOrSeries: listing.key, currencyOrUnit: currency, interval: OPTIONS_EXPORT_INTERVAL },
2756
2821
  // Exports state each decimal's unit in its header and end every row with the spot and dates it is as of.
2757
2822
  columns: [
@@ -2763,6 +2828,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2763
2828
  { key: "bid", header: "Bid" },
2764
2829
  { key: "ask", header: "Ask" },
2765
2830
  { key: "iv", header: "IV (annualized decimal)" },
2831
+ { key: "ivSource", header: "IV source" },
2766
2832
  { key: "delta", header: "Delta (decimal)" },
2767
2833
  { key: "volume", header: "Vol" },
2768
2834
  { key: "openInterest", header: "OI" },
@@ -2770,8 +2836,34 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2770
2836
  { key: "spotBasis", header: "Spot basis" },
2771
2837
  { key: "spotAsOf", header: "Spot as of" },
2772
2838
  { key: "openInterestAsOf", header: "OI as of" },
2839
+ // A venue's marks and its coin prices (Deribit's BTC and ETH options).
2840
+ ...(marked ? [
2841
+ { key: "mark", header: "Mark (USD)" }, { key: "gamma", header: "Gamma (per 1.00)" },
2842
+ { key: "vega", header: "Vega (USD per vol point)" }, { key: "theta", header: "Theta (USD per day)" },
2843
+ { key: "forward", header: "Forward" }, { key: "expiresAt", header: "Settles" },
2844
+ ] : []),
2845
+ ...(coin ? [
2846
+ { key: "coinBid", header: `Bid (${coin})` }, { key: "coinAsk", header: `Ask (${coin})` },
2847
+ { key: "coinMark", header: `Mark (${coin})` }, { key: "coinLast", header: `Last (${coin})` },
2848
+ ] : []),
2773
2849
  ],
2774
- textColumns: [
2850
+ // A coin's options are quoted in the coin: its bid, ask and mark, then the mark in dollars and the venue's greeks.
2851
+ textColumns: coin ? [
2852
+ { key: "side", header: "Side" },
2853
+ { key: "contract", header: "Contract", shrink: false },
2854
+ { key: "strike", header: "Strike", align: "right" },
2855
+ { key: "coinBid", header: `Bid ${coin}`, align: "right", format: formatCoinPremiumCell },
2856
+ { key: "coinAsk", header: `Ask ${coin}`, align: "right", format: formatCoinPremiumCell },
2857
+ { key: "coinMark", header: `Mark ${coin}`, align: "right", format: formatCoinPremiumCell },
2858
+ { key: "mark", header: "Mark $", align: "right", format: formatOptionDollarCell },
2859
+ { key: "iv", header: "IV", align: "right", format: (value, row) => formatOptionIvCell(value, row) },
2860
+ { key: "delta", header: "Delta", align: "right", format: formatOptionDeltaCell },
2861
+ { key: "gamma", header: "Gamma", align: "right", format: formatOptionGammaCell, optional: true, dropPriority: 3 },
2862
+ { key: "vega", header: "Vega $", align: "right", format: formatOptionDollarCell, optional: true, dropPriority: 2 },
2863
+ { key: "theta", header: "Theta $", align: "right", format: formatOptionDollarCell, optional: true, dropPriority: 2 },
2864
+ { key: "volume", header: "Vol", align: "right", format: formatCountCell, optional: true, dropPriority: 1 },
2865
+ { key: "openInterest", header: "OI", align: "right", format: formatCountCell, optional: true, dropPriority: 1 },
2866
+ ] : [
2775
2867
  { key: "side", header: "Side" },
2776
2868
  { key: "contract", header: "Contract", shrink: false },
2777
2869
  // The contract symbol already carries the date, so this goes first when the table is narrow.
@@ -2780,7 +2872,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2780
2872
  { key: "last", header: "Last", align: "right" },
2781
2873
  { key: "bid", header: "Bid", align: "right", format: (_value, row) => formatOptionQuoteCell(row, "bid") },
2782
2874
  { key: "ask", header: "Ask", align: "right", format: (_value, row) => formatOptionQuoteCell(row, "ask") },
2783
- { key: "iv", header: "IV", align: "right", format: formatOptionIvCell },
2875
+ { key: "iv", header: "IV", align: "right", format: (value, row) => formatOptionIvCell(value, row) },
2784
2876
  { key: "delta", header: "Delta", align: "right", format: formatOptionDeltaCell },
2785
2877
  { key: "volume", header: "Vol", align: "right", format: formatCountCell, optional: true, dropPriority: 1 },
2786
2878
  { key: "openInterest", header: "OI", align: "right", format: formatCountCell, optional: true, dropPriority: 1 },
@@ -3204,7 +3296,7 @@ export const marketDataCliCommands: BuiltinCliCommandDef[] = [
3204
3296
  usage: [OPTIONS_USAGE, LEAPS_USAGE],
3205
3297
  options: [
3206
3298
  {
3207
- flags: `--expiration <${OPTION_EXPIRATION_PLACEHOLDER}>`,
3299
+ flags: `--expiration <${OPTION_EXPIRATION_PLACEHOLDER}>, --expiry <${OPTION_EXPIRATION_PLACEHOLDER}>`,
3208
3300
  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",
3209
3301
  },
3210
3302
  EXCHANGE_OPTION,