gloomberb 0.18.3 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (886) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/src/account/checkout-handoff.tsx +225 -0
  6. package/src/account/device-signin-dialog.tsx +2 -2
  7. package/src/account/device-signin.ts +2 -2
  8. package/src/account/upgrade-dialog.tsx +1 -1
  9. package/src/api-client/askg.ts +2 -2
  10. package/src/api-client/auth.ts +2 -2
  11. package/src/api-client/central-bank-rates.ts +6 -0
  12. package/src/api-client/collections.ts +5 -1
  13. package/src/api-client/cot.ts +2 -0
  14. package/src/api-client/crypto-etf-flows.ts +37 -0
  15. package/src/api-client/crypto-markets.ts +60 -0
  16. package/src/api-client/data.ts +84 -5
  17. package/src/api-client/doe.ts +15 -0
  18. package/src/api-client/equity-screener.ts +28 -0
  19. package/src/api-client/exchange-announcements.ts +38 -0
  20. package/src/api-client/fund-facts.ts +39 -0
  21. package/src/api-client/futures-curve.ts +9 -1
  22. package/src/api-client/hiring.ts +301 -0
  23. package/src/api-client/index.ts +22 -5
  24. package/src/api-client/market-discovery.ts +14 -0
  25. package/src/api-client/members.ts +6 -0
  26. package/src/api-client/mna.ts +6 -0
  27. package/src/api-client/paths.ts +18 -1
  28. package/src/api-client/request.ts +21 -4
  29. package/src/api-client/short-side-publications.ts +37 -0
  30. package/src/api-client/socket.ts +64 -4
  31. package/src/api-client/swap-curve.ts +35 -0
  32. package/src/api-client/themes.ts +7 -1
  33. package/src/api-client/types.ts +90 -2
  34. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  35. package/src/app/runtime/desktop-deeplink.ts +5 -5
  36. package/src/app/runtime/plugin-bindings.ts +2 -2
  37. package/src/app/runtime/startup.ts +13 -0
  38. package/src/app/star-prompt/status-line.tsx +2 -2
  39. package/src/architecture/core-builtin-allowlist.json +5 -2
  40. package/src/architecture/ui-literals-allowlist.json +3 -3
  41. package/src/architecture/ui-tokens-allowlist.json +1 -1
  42. package/src/brokers/broker-portfolio-sync.ts +37 -0
  43. package/src/brokers/directory.ts +11 -0
  44. package/src/brokers/logos.ts +3 -1
  45. package/src/brokers/signed-in/adapter.ts +304 -26
  46. package/src/brokers/signed-in/client.ts +14 -2
  47. package/src/brokers/signed-in/connect.ts +10 -2
  48. package/src/brokers/sync-broker-instance.ts +9 -1
  49. package/src/capabilities/chart-series.ts +22 -6
  50. package/src/cli/bank-section.ts +1 -1
  51. package/src/cli/base-converter.ts +23 -14
  52. package/src/cli/central-bank-events.ts +1 -1
  53. package/src/cli/command-options.ts +59 -4
  54. package/src/cli/commands/api.ts +9 -6
  55. package/src/cli/commands/broker.ts +2 -2
  56. package/src/cli/commands/command-utils.ts +2 -2
  57. package/src/cli/commands/crypto-hints.ts +7 -20
  58. package/src/cli/commands/fred-series.ts +4 -2
  59. package/src/cli/commands/keybindings.ts +2 -2
  60. package/src/cli/commands/market.ts +1117 -264
  61. package/src/cli/commands/news-hints.ts +2 -2
  62. package/src/cli/commands/news-search.ts +59 -6
  63. package/src/cli/commands/options-leaps.ts +41 -26
  64. package/src/cli/commands/overview.ts +121 -48
  65. package/src/cli/commands/plugins.ts +9 -9
  66. package/src/cli/commands/remote.ts +13 -10
  67. package/src/cli/commands/search.ts +64 -44
  68. package/src/cli/commands/system.ts +27 -19
  69. package/src/cli/commands/themes.ts +1 -1
  70. package/src/cli/commands/ticker.ts +192 -47
  71. package/src/cli/context.ts +3 -2
  72. package/src/cli/desktop-pane-shot-view.ts +2 -2
  73. package/src/cli/desktop-pane-shot.ts +1 -1
  74. package/src/cli/earnings-calendar.ts +4 -4
  75. package/src/cli/entry.ts +18 -1
  76. package/src/cli/errors.ts +20 -2
  77. package/src/cli/exit-codes.ts +1 -1
  78. package/src/cli/export-source.ts +10 -4
  79. package/src/cli/freshness.ts +2 -8
  80. package/src/cli/fx-forward.ts +130 -0
  81. package/src/cli/fx-pair.ts +10 -9
  82. package/src/cli/glossary.ts +64 -20
  83. package/src/cli/help.ts +19 -13
  84. package/src/cli/history-export.ts +126 -0
  85. package/src/cli/history-rows.ts +196 -43
  86. package/src/cli/index-roots.ts +5 -45
  87. package/src/cli/index.ts +24 -18
  88. package/src/cli/known-gaps.ts +118 -25
  89. package/src/cli/listing-arg.ts +300 -41
  90. package/src/cli/name-entries.ts +30 -18
  91. package/src/cli/native-smoke.ts +2 -0
  92. package/src/cli/not-a-ticker.ts +19 -9
  93. package/src/cli/opentui-libc.ts +5 -0
  94. package/src/cli/options.ts +12 -0
  95. package/src/cli/pane-functions/capabilities.ts +75 -20
  96. package/src/cli/pane-functions/catalog.ts +24 -23
  97. package/src/cli/pane-functions/discovery.ts +1 -1
  98. package/src/cli/pane-functions/dom.ts +10 -7
  99. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  100. package/src/cli/pane-functions/freshness.ts +174 -23
  101. package/src/cli/pane-functions/function-help.ts +66 -27
  102. package/src/cli/pane-functions/headless.ts +24 -11
  103. package/src/cli/pane-functions/index.ts +18 -16
  104. package/src/cli/pane-functions/options.ts +22 -2
  105. package/src/cli/pane-functions/report-notices.ts +12 -4
  106. package/src/cli/pane-functions/report.ts +5 -5
  107. package/src/cli/pane-functions/resolver.ts +47 -10
  108. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  109. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  110. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  111. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  112. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  113. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  114. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  115. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  116. package/src/cli/pane-functions/shot-options.ts +8 -3
  117. package/src/cli/peso-dollar-rates.ts +79 -0
  118. package/src/cli/quote-answer.ts +38 -3
  119. package/src/cli/report-tables.ts +61 -16
  120. package/src/cli/restore-plugins.ts +29 -14
  121. package/src/cli/result.ts +111 -22
  122. package/src/cli/series-search.ts +5 -5
  123. package/src/cli/statement-filings.ts +19 -0
  124. package/src/cli/suffixed-listing-rows.ts +49 -0
  125. package/src/cli/symbol-args.ts +50 -15
  126. package/src/cli/symbol-cells.ts +120 -0
  127. package/src/cli/symbol-list.ts +198 -68
  128. package/src/cli/symbol-rows.ts +131 -25
  129. package/src/cli/ticker-resolution.ts +108 -11
  130. package/src/cli/treasury-yields.ts +5 -5
  131. package/src/cli/types.ts +2 -0
  132. package/src/cli/uncovered-instrument.ts +3 -3
  133. package/src/cli/unknown-command.ts +6 -6
  134. package/src/components/chart/composite/chart-layout.ts +131 -0
  135. package/src/components/chart/composite/composite-chart.tsx +373 -16
  136. package/src/components/chart/composite/interactions.ts +7 -2
  137. package/src/components/chart/composite/legend.tsx +75 -3
  138. package/src/components/chart/composite/levels.ts +5 -0
  139. package/src/components/chart/composite/panel-gestures.ts +41 -0
  140. package/src/components/chart/composite/panel-labels.ts +2 -1
  141. package/src/components/chart/composite/panel-surface.tsx +305 -11
  142. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  143. package/src/components/chart/composite/rasterizer.ts +44 -19
  144. package/src/components/chart/composite/scene.ts +16 -4
  145. package/src/components/chart/composite/text-renderer.ts +48 -21
  146. package/src/components/chart/composite/toolbar.tsx +52 -5
  147. package/src/components/chart/composite/types.ts +13 -0
  148. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  149. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  150. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  151. package/src/components/chart/composite/value-scale.ts +149 -0
  152. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  153. package/src/components/chart/core/pointer.ts +2 -0
  154. package/src/components/chart-table/index.ts +2 -0
  155. package/src/components/chart-table/read.tsx +74 -0
  156. package/src/components/command-bar/commands/collection-list.ts +41 -19
  157. package/src/components/command-bar/commands/collection.ts +9 -3
  158. package/src/components/command-bar/commands/direct/index.ts +1 -1
  159. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  160. package/src/components/command-bar/pane-templates/items.ts +59 -6
  161. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  162. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  163. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  164. package/src/components/command-bar/routes/root/results.ts +18 -4
  165. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  166. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  167. package/src/components/command-bar/routes/root/selection.ts +6 -1
  168. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  169. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  170. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  171. package/src/components/command-bar/selection-runtime.ts +50 -10
  172. package/src/components/command-bar/surface/index.tsx +24 -2
  173. package/src/components/command-bar/view-model.ts +7 -0
  174. package/src/components/command-bar/workflow/broker.ts +2 -2
  175. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  176. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  177. package/src/components/command-bar/workflow/fields.ts +8 -2
  178. package/src/components/command-bar/workflow/ops.ts +18 -4
  179. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  180. package/src/components/command-bar/workflow/submit.ts +3 -2
  181. package/src/components/command-bar/workflow/tickers.ts +5 -1
  182. package/src/components/company-logo.tsx +39 -0
  183. package/src/components/data-table/sections.ts +4 -2
  184. package/src/components/form-modal/confirm.tsx +2 -1
  185. package/src/components/form-modal/request.ts +5 -0
  186. package/src/components/form-modal/routes.ts +4 -1
  187. package/src/components/index.ts +12 -6
  188. package/src/components/layout/header.tsx +7 -6
  189. package/src/components/layout/market-summary.ts +9 -6
  190. package/src/components/layout/pane/capture-status.ts +1 -1
  191. package/src/components/layout/pane/footer/model.ts +11 -5
  192. package/src/components/layout/shell/chrome.ts +19 -6
  193. package/src/components/layout/shell/index.tsx +2 -1
  194. package/src/components/layout/shell/pane/layers.tsx +19 -1
  195. package/src/components/layout/status-bar.tsx +2 -2
  196. package/src/components/market-board/index.tsx +11 -3
  197. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  198. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  199. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  200. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  201. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  202. package/src/components/pane-settings-dialog/value.ts +8 -1
  203. package/src/components/pane-settings-dialog.tsx +44 -13
  204. package/src/components/sign-in-code-panel.tsx +27 -19
  205. package/src/components/ui/column-grid.tsx +48 -4
  206. package/src/components/ui/country-flag-art.tsx +180 -0
  207. package/src/components/ui/country-flag.tsx +118 -12
  208. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  209. package/src/components/ui/data-table/opentui/model.ts +109 -2
  210. package/src/components/ui/data-table/types.ts +1 -1
  211. package/src/components/ui/display.tsx +5 -1
  212. package/src/components/ui/index.ts +3 -1
  213. package/src/components/ui/logo-mark.tsx +11 -2
  214. package/src/components/ui/query-bar.tsx +1 -1
  215. package/src/components/ui/row-notes.ts +79 -0
  216. package/src/core/state/app/layout.ts +4 -4
  217. package/src/data/cached-query.ts +8 -1
  218. package/src/data/config/chart-settings.ts +3 -3
  219. package/src/data/config/home.ts +10 -2
  220. package/src/data/config/layout.ts +4 -1
  221. package/src/data/config/store/node.ts +4 -0
  222. package/src/data/config/store/normalize.ts +13 -3
  223. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  224. package/src/data/json-storage.ts +2 -0
  225. package/src/data/saved-copies.ts +84 -0
  226. package/src/docs/snapshot.json +65 -32
  227. package/src/i18n/es.ts +29 -12
  228. package/src/i18n/ja.ts +29 -12
  229. package/src/i18n/ko.ts +29 -12
  230. package/src/i18n/zh-cn.ts +29 -12
  231. package/src/i18n/zh-tw.ts +29 -12
  232. package/src/layout/desks.ts +1 -1
  233. package/src/layout/launch-layout.ts +1 -1
  234. package/src/layout/pane-manager/floating-actions.ts +5 -3
  235. package/src/layout/pane-manager/floating.ts +43 -1
  236. package/src/layout/pane-manager/index.ts +2 -0
  237. package/src/layout/selected-ticker.ts +74 -0
  238. package/src/market-data/depositary-pair.ts +251 -0
  239. package/src/market-data/futures-board.ts +1 -1
  240. package/src/market-data/futures-contract.ts +124 -40
  241. package/src/market-data/fx-closes.ts +17 -2
  242. package/src/market-data/hooks.tsx +19 -11
  243. package/src/market-data/market/change-basis.ts +49 -7
  244. package/src/market-data/market/freshness.ts +34 -5
  245. package/src/market-data/market/period-return.ts +163 -0
  246. package/src/market-data/market/trading-sessions.ts +13 -0
  247. package/src/market-data/market/year-to-date.ts +8 -13
  248. package/src/market-data/performance.ts +20 -14
  249. package/src/market-data/perpetual-premium.ts +32 -0
  250. package/src/market-data/published-apac-sessions.ts +2 -1
  251. package/src/market-data/published-futures-sessions.ts +69 -0
  252. package/src/market-data/quotes/contributions.ts +5 -1
  253. package/src/market-data/quotes/freshness.ts +42 -0
  254. package/src/market-data/quotes/intraday-bar.ts +37 -0
  255. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  256. package/src/market-data/quotes/resolution.ts +4 -2
  257. package/src/market-data/tax-equivalent.ts +1 -1
  258. package/src/market-data/ticker-price-returns.ts +3 -1
  259. package/src/news/aggregator.ts +5 -1
  260. package/src/news/news-model.ts +4 -0
  261. package/src/news/types.ts +11 -0
  262. package/src/notifications/app-notifier.ts +1 -1
  263. package/src/plugins/auto-update.ts +2 -2
  264. package/src/plugins/builtin/account-management/index.tsx +1 -0
  265. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  266. package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
  267. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  268. package/src/plugins/builtin/alerts/cli.ts +485 -76
  269. package/src/plugins/builtin/alerts/command.ts +5 -10
  270. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  271. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  272. package/src/plugins/builtin/alerts/events.ts +107 -5
  273. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  274. package/src/plugins/builtin/alerts/format.ts +2 -1
  275. package/src/plugins/builtin/alerts/headless.ts +100 -39
  276. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  277. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  278. package/src/plugins/builtin/alerts/index.tsx +45 -18
  279. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  280. package/src/plugins/builtin/alerts/levels.ts +3 -3
  281. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  282. package/src/plugins/builtin/alerts/price.ts +35 -0
  283. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  284. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  285. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  286. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  287. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  288. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  289. package/src/plugins/builtin/alerts/storage.ts +13 -10
  290. package/src/plugins/builtin/alerts/targets.ts +12 -3
  291. package/src/plugins/builtin/analytics/index.tsx +8 -2
  292. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  293. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  294. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  295. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  296. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  297. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  298. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  299. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  300. package/src/plugins/builtin/attention/pane.tsx +6 -2
  301. package/src/plugins/builtin/awards/headless.ts +7 -3
  302. package/src/plugins/builtin/awards/model.ts +18 -0
  303. package/src/plugins/builtin/awards/pane.tsx +6 -3
  304. package/src/plugins/builtin/backtest/headless.ts +3 -3
  305. package/src/plugins/builtin/backtest/rules.ts +41 -5
  306. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  307. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  308. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  309. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  310. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  311. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  312. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  313. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  314. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  315. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  316. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  317. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  318. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  319. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  320. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  321. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  322. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  323. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  324. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  325. package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
  326. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  327. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  328. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  329. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  330. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  331. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  332. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  333. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  334. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  335. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  336. package/src/plugins/builtin/catalysts/model.ts +49 -4
  337. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  338. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  339. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  340. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  341. package/src/plugins/builtin/changelog/index.tsx +1 -0
  342. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  343. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  344. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  345. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  346. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  347. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  348. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  349. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  350. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  351. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  352. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  353. package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
  354. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  355. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  356. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  357. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  358. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  359. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  360. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  361. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  362. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  363. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  364. package/src/plugins/builtin/chat/people.ts +1 -1
  365. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  366. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  367. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  368. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  369. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  370. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  371. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  372. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  373. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  374. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  375. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  376. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  377. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  378. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  379. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  380. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  381. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  382. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  383. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  384. package/src/plugins/builtin/company-attention/client.ts +117 -1
  385. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  386. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  387. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  388. package/src/plugins/builtin/company-attention/model.ts +33 -7
  389. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  390. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  391. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  392. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  393. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  394. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  395. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  396. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  397. package/src/plugins/builtin/composite-plugins.ts +2 -1
  398. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  399. package/src/plugins/builtin/connections/index.ts +1 -0
  400. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  401. package/src/plugins/builtin/correlation/headless.ts +5 -3
  402. package/src/plugins/builtin/cot/headless.ts +28 -6
  403. package/src/plugins/builtin/cot/model.ts +12 -0
  404. package/src/plugins/builtin/cot/pane.tsx +3 -2
  405. package/src/plugins/builtin/cpi/headless.ts +5 -1
  406. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  407. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  408. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  409. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  410. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  411. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  412. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  413. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  414. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  415. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  416. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  417. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  418. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  419. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  420. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  421. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  422. package/src/plugins/builtin/debug/index.tsx +1 -0
  423. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  424. package/src/plugins/builtin/docs/index.tsx +1 -1
  425. package/src/plugins/builtin/docs/pane.tsx +2 -2
  426. package/src/plugins/builtin/docs/targets.ts +1 -1
  427. package/src/plugins/builtin/doe/client.ts +5 -1
  428. package/src/plugins/builtin/doe/headless.ts +12 -6
  429. package/src/plugins/builtin/doe/model.ts +43 -6
  430. package/src/plugins/builtin/doe/pane.tsx +18 -11
  431. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  432. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  433. package/src/plugins/builtin/earnings/board.tsx +253 -50
  434. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  435. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  436. package/src/plugins/builtin/earnings/client.ts +4 -3
  437. package/src/plugins/builtin/earnings/headless.ts +53 -15
  438. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  439. package/src/plugins/builtin/earnings/index.tsx +15 -22
  440. package/src/plugins/builtin/earnings/model.ts +17 -12
  441. package/src/plugins/builtin/earnings/scope.ts +89 -0
  442. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  443. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  444. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  445. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  446. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  447. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  448. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  449. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  450. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  451. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  452. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  453. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  454. package/src/plugins/builtin/econ/index.tsx +112 -25
  455. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  456. package/src/plugins/builtin/econ/types.ts +32 -1
  457. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  458. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  459. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  460. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  461. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  462. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  463. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  464. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  465. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  466. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  467. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  468. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  469. package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
  470. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  471. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  472. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  473. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  474. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  475. package/src/plugins/builtin/exposure/headless.ts +51 -6
  476. package/src/plugins/builtin/exposure/index.tsx +28 -2
  477. package/src/plugins/builtin/exposure/model.ts +7 -0
  478. package/src/plugins/builtin/exposure/pane.tsx +6 -1
  479. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  480. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  481. package/src/plugins/builtin/futures/model.ts +10 -9
  482. package/src/plugins/builtin/futures/returns.ts +8 -36
  483. package/src/plugins/builtin/futures/table.tsx +1 -1
  484. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  485. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  486. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  487. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  488. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  489. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  490. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  491. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  492. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  493. package/src/plugins/builtin/gpu/headless.ts +9 -4
  494. package/src/plugins/builtin/help/index.tsx +13 -3
  495. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  496. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  497. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  498. package/src/plugins/builtin/holders/client.ts +13 -1
  499. package/src/plugins/builtin/holders/format.ts +28 -17
  500. package/src/plugins/builtin/holders/headless.ts +46 -7
  501. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  502. package/src/plugins/builtin/holders/pane.tsx +79 -15
  503. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  504. package/src/plugins/builtin/holders/table-model.ts +2 -1
  505. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  506. package/src/plugins/builtin/insider/headless.ts +1 -1
  507. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  508. package/src/plugins/builtin/insider/signals.tsx +1 -1
  509. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  510. package/src/plugins/builtin/iv-history/client.ts +20 -0
  511. package/src/plugins/builtin/iv-history/headless.ts +4 -4
  512. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  513. package/src/plugins/builtin/iv-history/model.ts +13 -4
  514. package/src/plugins/builtin/iv-history/series.ts +3 -1
  515. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  516. package/src/plugins/builtin/jobs/model.ts +4 -15
  517. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  518. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  519. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  520. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  521. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  522. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  523. package/src/plugins/builtin/macro-day/model.ts +29 -8
  524. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  525. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  526. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  527. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  528. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  529. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  530. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  531. package/src/plugins/builtin/market-movers/client.ts +33 -19
  532. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  533. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  534. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  535. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  536. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  537. package/src/plugins/builtin/market-movers/table.ts +4 -1
  538. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  539. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  540. package/src/plugins/builtin/members/headless.ts +6 -5
  541. package/src/plugins/builtin/members/pane.tsx +11 -4
  542. package/src/plugins/builtin/mna/client.ts +1 -0
  543. package/src/plugins/builtin/mna/detail.tsx +20 -32
  544. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  545. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  546. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  547. package/src/plugins/builtin/mna/headless.ts +6 -13
  548. package/src/plugins/builtin/mna/model.ts +93 -15
  549. package/src/plugins/builtin/mna/pane.tsx +5 -4
  550. package/src/plugins/builtin/news/headless.ts +12 -6
  551. package/src/plugins/builtin/news/index.tsx +10 -1
  552. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  553. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  554. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  555. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  556. package/src/plugins/builtin/notes/cli.ts +49 -14
  557. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  558. package/src/plugins/builtin/options/carry.ts +2 -2
  559. package/src/plugins/builtin/options/index.tsx +1 -1
  560. package/src/plugins/builtin/options/view.tsx +10 -10
  561. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  562. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  563. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  564. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  565. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  566. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  567. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  568. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  569. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  570. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  571. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  572. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  573. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  574. package/src/plugins/builtin/perps/freshness.ts +8 -5
  575. package/src/plugins/builtin/perps/headless.ts +3 -1
  576. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  577. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  578. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  579. package/src/plugins/builtin/perps/pane.tsx +36 -17
  580. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  581. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  582. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  583. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  584. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  585. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  586. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  587. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  588. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  589. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  590. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  591. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  592. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  593. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  594. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  595. package/src/plugins/builtin/power/client.ts +4 -1
  596. package/src/plugins/builtin/power/evidence.ts +22 -7
  597. package/src/plugins/builtin/power/gas.tsx +5 -1
  598. package/src/plugins/builtin/power/pane.tsx +8 -1
  599. package/src/plugins/builtin/power/prices.tsx +10 -3
  600. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  601. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  602. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  603. package/src/plugins/builtin/research/event-model.ts +3 -1
  604. package/src/plugins/builtin/research/event-sources.ts +12 -4
  605. package/src/plugins/builtin/research/index.tsx +2 -1
  606. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  607. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  608. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  609. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  610. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  611. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  612. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  613. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  614. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  615. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  616. package/src/plugins/builtin/sec/forms.ts +13 -0
  617. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  618. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  619. package/src/plugins/builtin/sec/headless.ts +85 -8
  620. package/src/plugins/builtin/sec/index.tsx +58 -12
  621. package/src/plugins/builtin/sectors/client.ts +2 -1
  622. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  623. package/src/plugins/builtin/series-inventory.ts +2 -0
  624. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  625. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  626. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  627. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  628. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  629. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  630. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  631. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  632. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  633. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  634. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  635. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  636. package/src/plugins/builtin/short-interest/client.ts +2 -0
  637. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  638. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  639. package/src/plugins/builtin/short-interest/model.ts +70 -19
  640. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  641. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  642. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  643. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  644. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  645. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  646. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  647. package/src/plugins/builtin/short-interest/types.ts +9 -0
  648. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  649. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  650. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  651. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  652. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  653. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  654. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  655. package/src/plugins/builtin/themes/headless.ts +8 -5
  656. package/src/plugins/builtin/themes/model.ts +14 -4
  657. package/src/plugins/builtin/themes/pane.tsx +24 -5
  658. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  659. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  660. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  661. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  662. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  663. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  664. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  665. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  666. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  667. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  668. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  669. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  670. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  671. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  672. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  673. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  674. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  675. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  676. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  677. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  678. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  679. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  680. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  681. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  682. package/src/plugins/builtin/vol-surface/client.ts +5 -4
  683. package/src/plugins/builtin/vol-surface/headless.ts +12 -3
  684. package/src/plugins/builtin/vol-surface/model.ts +4 -2
  685. package/src/plugins/builtin/volatility/model.ts +5 -10
  686. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  687. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  688. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  689. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  690. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  691. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  692. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  693. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  694. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  695. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  696. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  697. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  698. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  699. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  700. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  701. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  702. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  703. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  704. package/src/plugins/bundle.ts +1 -1
  705. package/src/plugins/catalog-browser.ts +2 -1
  706. package/src/plugins/compat.ts +3 -3
  707. package/src/plugins/dependencies.ts +75 -14
  708. package/src/plugins/extracted-plugins.ts +132 -34
  709. package/src/plugins/host-link.ts +149 -34
  710. package/src/plugins/installer.ts +35 -10
  711. package/src/plugins/loader.ts +206 -38
  712. package/src/plugins/manager-node.ts +2 -2
  713. package/src/plugins/marketplace/deactivation.ts +22 -0
  714. package/src/plugins/marketplace/model.ts +2 -2
  715. package/src/plugins/marketplace/packs.ts +1 -1
  716. package/src/plugins/ownership.ts +1 -1
  717. package/src/plugins/peer-retry.ts +155 -0
  718. package/src/plugins/registry/contributions.ts +3 -1
  719. package/src/plugins/registry/index.ts +4 -3
  720. package/src/plugins/registry/plugin-state.ts +3 -0
  721. package/src/plugins/seed-notice.ts +20 -0
  722. package/src/plugins/shortcut-argument.ts +39 -0
  723. package/src/portfolio/allocation.ts +1 -1
  724. package/src/portfolio/collection-name.ts +31 -0
  725. package/src/portfolio/column-values.ts +10 -8
  726. package/src/portfolio/cost-fx.ts +296 -19
  727. package/src/portfolio/manual-lots.ts +75 -0
  728. package/src/portfolio/mutations.ts +60 -22
  729. package/src/portfolio/suffixed-listings.ts +209 -0
  730. package/src/portfolio/totals-currency.ts +24 -0
  731. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  732. package/src/public/time-series.ts +11 -8
  733. package/src/remote/schema.ts +1 -1
  734. package/src/renderers/browser/config-host.ts +3 -0
  735. package/src/renderers/browser/main.tsx +23 -3
  736. package/src/renderers/dom/boot-frame-page.ts +187 -0
  737. package/src/renderers/dom/boot-frame.ts +237 -0
  738. package/src/renderers/dom/build-assets.ts +46 -8
  739. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  740. package/src/renderers/dom/host/ascii-text.ts +16 -2
  741. package/src/renderers/dom/host/box.tsx +43 -2
  742. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  743. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  744. package/src/renderers/dom/host/image-surface.tsx +49 -0
  745. package/src/renderers/dom/host/media-surface.tsx +24 -18
  746. package/src/renderers/dom/host/mouse.ts +30 -0
  747. package/src/renderers/dom/host/size-observer.ts +1 -1
  748. package/src/renderers/dom/host/style.ts +1 -1
  749. package/src/renderers/dom/styles.css +76 -0
  750. package/src/renderers/dom/test-utils.tsx +2 -1
  751. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  752. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  753. package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
  754. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  755. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  756. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  757. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  758. package/src/renderers/electrobun/bun/index.ts +11 -1
  759. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  760. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  761. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  762. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  763. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  764. package/src/renderers/electrobun/view/config-host.ts +3 -0
  765. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  766. package/src/renderers/electrobun/view/main.tsx +30 -4
  767. package/src/renderers/electrobun/view/news-source.ts +5 -5
  768. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  769. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  770. package/src/renderers/opentui/browser-open.ts +88 -0
  771. package/src/renderers/opentui/host.tsx +5 -14
  772. package/src/renderers/opentui/image/loader.ts +3 -2
  773. package/src/renderers/opentui/native-smoke.ts +10 -1
  774. package/src/renderers/opentui/pane-image/index.ts +2 -1
  775. package/src/renderers/opentui/render-lib.ts +253 -0
  776. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  777. package/src/renderers/opentui/start.tsx +1 -1
  778. package/src/renderers/share/layout-view.tsx +2 -2
  779. package/src/renderers/share/main.tsx +4 -4
  780. package/src/renderers/share/view.tsx +1 -1
  781. package/src/series/resolve.ts +22 -6
  782. package/src/series/standalone.ts +30 -2
  783. package/src/series/types.ts +8 -1
  784. package/src/shares/api.ts +4 -1
  785. package/src/shares/pane.ts +1 -1
  786. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  787. package/src/sources/gloomberb-cloud/index.ts +32 -16
  788. package/src/sources/gloomberb-cloud/news.ts +39 -0
  789. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  790. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  791. package/src/sources/listing-symbols.ts +37 -0
  792. package/src/sources/provider-errors.ts +16 -2
  793. package/src/sources/provider-router/financial-routes.ts +21 -3
  794. package/src/sources/provider-router/financials.ts +15 -2
  795. package/src/sources/provider-router/history.ts +30 -8
  796. package/src/sources/provider-router/primary.ts +1 -1
  797. package/src/state/app/bootstrap.ts +23 -0
  798. package/src/state/hooks/inline-tickers.ts +30 -5
  799. package/src/sync/controller.ts +1 -1
  800. package/src/sync/core-contributors.ts +46 -14
  801. package/src/team/collections-sync.ts +2 -1
  802. package/src/team/collections.ts +178 -17
  803. package/src/telemetry/crash-reports.ts +17 -4
  804. package/src/test-support/builtin-panes.ts +1 -1
  805. package/src/theme/colors.ts +3 -30
  806. package/src/theme/ui-tokens.ts +37 -1
  807. package/src/tickers/company-name-listing.ts +210 -33
  808. package/src/tickers/index-roots.ts +47 -0
  809. package/src/tickers/instrument-label.ts +5 -1
  810. package/src/tickers/metadata.ts +10 -0
  811. package/src/tickers/perpetual-listing.ts +5 -2
  812. package/src/tickers/search/home-listing.ts +75 -0
  813. package/src/tickers/search/index.ts +76 -27
  814. package/src/tickers/search/ranking.ts +54 -4
  815. package/src/tickers/search/upsert.ts +29 -0
  816. package/src/tickers/terminal-codes.ts +416 -40
  817. package/src/time-series/bar-aggregation.ts +243 -0
  818. package/src/time-series/base-series.ts +307 -0
  819. package/src/time-series/chart-bounds.ts +349 -0
  820. package/src/time-series/chart-seed.ts +142 -0
  821. package/src/time-series/economic.ts +5 -0
  822. package/src/time-series/fundamentals.ts +18 -3
  823. package/src/time-series/history-acquisition.ts +499 -0
  824. package/src/time-series/leverage.ts +100 -0
  825. package/src/time-series/market-resolution.ts +4 -2
  826. package/src/time-series/market.ts +2 -1
  827. package/src/time-series/price-comparison.ts +175 -30
  828. package/src/time-series/range.ts +9 -1
  829. package/src/time-series/resolution.ts +174 -16
  830. package/src/time-series/resolve-context.ts +157 -0
  831. package/src/time-series/resolve.ts +126 -1577
  832. package/src/time-series/series-name.ts +38 -0
  833. package/src/time-series/series-presentation.ts +208 -0
  834. package/src/time-series/spec.ts +11 -6
  835. package/src/time-series/studies.ts +109 -12
  836. package/src/time-series/tail-reconcile.ts +121 -0
  837. package/src/time-series/types.ts +29 -2
  838. package/src/time-series/use-chart-resolution.ts +4 -5
  839. package/src/types/broker.ts +10 -0
  840. package/src/types/config.ts +14 -0
  841. package/src/types/data-provider.ts +14 -0
  842. package/src/types/exchange-rate.ts +6 -0
  843. package/src/types/financials.ts +104 -7
  844. package/src/types/headless.ts +76 -6
  845. package/src/types/instrument.ts +3 -0
  846. package/src/types/plugin.ts +65 -8
  847. package/src/types/price-history.ts +2 -0
  848. package/src/types/ticker.ts +13 -0
  849. package/src/types/trading.ts +59 -1
  850. package/src/ui/ascii-font.ts +13 -1
  851. package/src/ui/host.tsx +6 -1
  852. package/src/updater/command-names.ts +175 -0
  853. package/src/updater/index.ts +10 -5
  854. package/src/utils/calendar-date.ts +32 -15
  855. package/src/utils/cash-runway.ts +241 -0
  856. package/src/utils/central-banks.ts +42 -0
  857. package/src/utils/cli-output.ts +259 -80
  858. package/src/utils/contract-month.ts +16 -0
  859. package/src/utils/crypto-pair.ts +61 -3
  860. package/src/utils/currency-units.ts +29 -0
  861. package/src/utils/datetime-format.ts +10 -0
  862. package/src/utils/debug-log.ts +1 -1
  863. package/src/utils/decimal-comma.ts +39 -6
  864. package/src/utils/exchange-announcements.ts +71 -0
  865. package/src/utils/exchange-rate-snapshot.ts +10 -0
  866. package/src/utils/financial-statements.ts +83 -4
  867. package/src/utils/format.ts +34 -16
  868. package/src/utils/fundamentals.ts +150 -34
  869. package/src/utils/fx-market-hours.ts +10 -1
  870. package/src/utils/latest-financial-period.ts +8 -0
  871. package/src/utils/linux-libc.ts +54 -0
  872. package/src/utils/market-capitalization.ts +111 -15
  873. package/src/utils/max-drawdown.ts +64 -0
  874. package/src/utils/network-failure.ts +83 -0
  875. package/src/utils/option-expiry.ts +139 -7
  876. package/src/utils/price-earnings.ts +11 -5
  877. package/src/utils/price-history.ts +18 -8
  878. package/src/utils/price-window.ts +131 -0
  879. package/src/utils/release-date.ts +47 -0
  880. package/src/utils/sec.ts +3 -0
  881. package/src/utils/throttled-fetch.ts +11 -4
  882. package/src/utils/trailing-eps.ts +67 -0
  883. package/src/utils/typed-text.ts +21 -0
  884. package/src/utils/utc-time.ts +24 -1
  885. package/src/version.ts +6 -0
  886. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -1,7 +1,10 @@
1
- import { formatPriceEarnings } from "../../../../utils/price-earnings";
1
+ import { formatPriceEarnings, NOT_MEANINGFUL } from "../../../../utils/price-earnings";
2
2
  import { convertMarketCapitalization } from "../../../../utils/market-capitalization";
3
3
  import { priceColor } from "../../../../theme/colors";
4
- import type { CompanyProfile, NextEarnings, Quote, TickerFinancials } from "../../../../types/financials";
4
+ import type { CompanyProfile, DepositaryPair, NextEarnings, Quote, TickerFinancials } from "../../../../types/financials";
5
+ import { adrRatioText } from "../../../../utils/depositary-receipt";
6
+ import { ratioCount } from "../../../../market-data/depositary-pair";
7
+ import { ADR_PAIR_TAB_ID, ADR_PAIR_TEMPLATE_ID } from "../adr-pair/model";
5
8
  import type { Portfolio, TickerPosition, TickerRecord } from "../../../../types/ticker";
6
9
  import type { BrokerInstanceConfig } from "../../../../types/config";
7
10
  import type { BrokerAccount } from "../../../../types/trading";
@@ -28,11 +31,12 @@ import { getPortfolioPositionMetrics, getPortfolioQuoteDisplay, resolvePortfolio
28
31
  import { listingDividendYield, liveForwardPE, liveMarketCapitalization, liveTrailingPE } from "../../../../market-data/quotes/live-valuation";
29
32
  import { atRegularSessionPrice } from "../../../../market-data/quotes/regular-session-valuation";
30
33
  import { formatReportedMoney } from "../../../../utils/reported-money";
31
- import { enterpriseValueCheck, fundamentalsCurrency, fundamentalsEpsCurrency, reportedEnterpriseValue } from "../../../../utils/fundamentals";
34
+ import { enterpriseValueCheck, enterpriseValueNotMeaningful, fundamentalsCurrency, fundamentalsEpsCurrency, reportedEnterpriseValue } from "../../../../utils/fundamentals";
32
35
  import { formatShortDate } from "../../../../utils/datetime-format";
33
36
  import { safeExternalUrl } from "../../../../utils/external-url";
34
37
  import type { FundBondFacts } from "../../../../api-client/fund-facts";
35
38
  import { bondFigures } from "../../../../market-data/bond-funds";
39
+ import { formatRunwayMonths, type CashRunway, type RunwayEstimate } from "../../../../utils/cash-runway";
36
40
 
37
41
  type CurrencyConverter = (value: number, fromCurrency: string) => number;
38
42
 
@@ -42,6 +46,8 @@ const SHORT_INTEREST: OverviewFunctionLink = { name: "Short Interest", tabId: "s
42
46
  const EARNINGS: OverviewFunctionLink = { name: "Earnings", templateId: "earnings-calendar-pane" };
43
47
  const DIVIDENDS: OverviewFunctionLink = { name: "Dividends", tabId: "dividend-yield", templateId: "dividend-yield-pane" };
44
48
  const FUND_FACTS: OverviewFunctionLink = { name: "Fund Facts", templateId: "sec-etf-pane" };
49
+ const FINANCIALS: OverviewFunctionLink = { name: "Financials", tabId: "financials", templateId: "financial-analysis-pane" };
50
+ const ADR_PAIR: OverviewFunctionLink = { name: "ADR vs Home", tabId: ADR_PAIR_TAB_ID, templateId: ADR_PAIR_TEMPLATE_ID };
45
51
 
46
52
  /** A bond fund's sponsor figures in a narrow grid: `SEC Yield 4.04% 2026-10-15`. */
47
53
  const BOND_STAT_LABELS = { secYield: "SEC Yield", yieldToWorst: "Yld to Worst" } as const;
@@ -108,6 +114,33 @@ function positionAccountLabel(position: TickerPosition, names: PositionAccountNa
108
114
  return `${positionAccountName(position, names)}${suffix}`;
109
115
  }
110
116
 
117
+ /** A runway measure as the grid reads it: `12.0 mo`, or `no burn`. */
118
+ function runwayText(estimate: RunwayEstimate): string {
119
+ return estimate.kind === "no-burn" ? "no burn" : formatRunwayMonths(estimate.months, "mo");
120
+ }
121
+
122
+ /**
123
+ * Months of cash for a company that burns it, at the latest quarter's burn
124
+ * with the trailing year's after it and the balance sheet's date where it
125
+ * fits (`12.0 mo qtr to 06-30 · TTM 14.4 mo`). It opens Financials, whose
126
+ * Liquidity rows show the cash and the monthly burn. A company whose
127
+ * trailing operating cash flow is nonnegative or unavailable has no row.
128
+ */
129
+ function runwayStat(runway: CashRunway | null | undefined): StatField | null {
130
+ if (runway?.trailing?.kind !== "months") return null;
131
+ const { quarter, trailing, periodEnd } = runway;
132
+ const dates = [periodEnd, periodEnd.slice(5)];
133
+ if (!quarter) return { label: "Runway", value: runwayText(trailing), detail: [...dates.map((date) => `TTM to ${date}`), "TTM"], link: FINANCIALS };
134
+ const ttm = ` · TTM ${runwayText(trailing)}`;
135
+ return {
136
+ label: "Runway",
137
+ value: runwayText(quarter),
138
+ // "12.0 mo TTM 14.4 mo" would read as one figure: a narrow column keeps "qtr" alone.
139
+ detail: [...dates.map((date) => `qtr to ${date}${ttm}`), `qtr${ttm}`, "qtr"],
140
+ link: FINANCIALS,
141
+ };
142
+ }
143
+
111
144
  export function buildOverviewStats({
112
145
  quote,
113
146
  fundamentals,
@@ -117,13 +150,15 @@ export function buildOverviewStats({
117
150
  marketCapExchangeRates = new Map(),
118
151
  nextEarnings,
119
152
  depositaryReceipt = false,
153
+ depositaryPair = null,
120
154
  today,
121
155
  dividend,
122
156
  bond = null,
157
+ runway = null,
123
158
  }: {
124
159
  quote: Quote | undefined;
125
160
  fundamentals: TickerFinancials["fundamentals"] | undefined;
126
- /** The currency the statements report in, for fundamentals that declare none. */
161
+ /** The currency the statements report in, for fundamentals that declare none on a listing that trades in it. */
127
162
  financialCurrency?: TickerFinancials["financialCurrency"];
128
163
  quoteCurrency: string;
129
164
  baseCurrency: string;
@@ -132,6 +167,8 @@ export function buildOverviewStats({
132
167
  nextEarnings?: NextEarnings;
133
168
  /** The share count is in depositary receipts, not ordinary shares. */
134
169
  depositaryReceipt?: boolean;
170
+ /** The receipt pair the listing is a side of, as Gloom Cloud serves it; `receiptSide` when the listing is the receipt. */
171
+ depositaryPair?: { pair: DepositaryPair; receiptSide: boolean } | null;
135
172
  /** The listing's calendar day, YYYY-MM-DD; dates before it are left out. */
136
173
  today?: string;
137
174
  /** The history the dividend yield reads (useOverviewDividend): a trailing one is measured from its cash, a forward one stops with it; without it the yield stands. */
@@ -141,9 +178,11 @@ export function buildOverviewStats({
141
178
  * distribution yield, not its SEC yield, which follows it with its date.
142
179
  */
143
180
  bond?: FundBondFacts | null;
181
+ /** Months of cash at the latest balance sheet (utils/cash-runway); shown when the company burns cash. */
182
+ runway?: CashRunway | null;
144
183
  }): StatField[] {
145
184
  const stats: StatField[] = [];
146
- const money = (value: number, perShare = false) => formatReportedMoney(value, fundamentalsCurrency({ fundamentals, financialCurrency }), perShare);
185
+ const money = (value: number, perShare = false) => formatReportedMoney(value, fundamentalsCurrency({ fundamentals, financialCurrency, quote }), perShare);
147
186
 
148
187
  // An index's 0 is volume nobody counts, not a quiet session: no Volume row.
149
188
  const volume = reportedQuoteVolume(quote);
@@ -164,15 +203,25 @@ export function buildOverviewStats({
164
203
  ),
165
204
  });
166
205
  }
206
+ // A count read off a 10-K or 10-Q cover says when it was counted; the source's own is undated.
207
+ const counted = (asOf: string | undefined) => (asOf ? { detail: [`as of ${asOf}`, `as of ${asOf.slice(5)}`] } : {});
167
208
  if (fundamentals?.sharesOutstanding) {
168
209
  stats.push({
169
210
  label: "Shares Out",
170
211
  value: formatCompact(fundamentals.sharesOutstanding),
171
- ...(depositaryReceipt ? { detail: ["ADR equivalent", "in ADRs"] } : {}),
212
+ ...(depositaryReceipt ? { detail: ["ADR equivalent", "in ADRs"] } : counted(fundamentals.sharesOutstandingAsOf)),
172
213
  });
173
214
  }
174
215
  if (finite(fundamentals?.floatShares) && fundamentals.floatShares > 0) {
175
- stats.push({ label: "Float", value: formatCompact(fundamentals.floatShares) });
216
+ stats.push({ label: "Float", value: formatCompact(fundamentals.floatShares), ...counted(fundamentals.floatSharesAsOf) });
217
+ }
218
+ // A receipt says how many shares it holds and a home line which receipt holds it, both opening ADR vs Home.
219
+ if (depositaryPair) {
220
+ const { pair, receiptSide } = depositaryPair;
221
+ const count = ratioCount(pair.ratio);
222
+ stats.push(receiptSide
223
+ ? { label: "ADR Ratio", value: `1:${count}`, detail: [adrRatioText(pair.ratio)!, `${count} sh per ADR`], link: ADR_PAIR }
224
+ : { label: "ADR", value: pair.receipt, detail: [`1 ADR = ${count} of these share${pair.ratio === 1 ? "" : "s"}`, `1:${count}`], link: ADR_PAIR });
176
225
  }
177
226
  const trailingPE = liveTrailingPE(quote, fundamentals);
178
227
  if (trailingPE != null) {
@@ -183,7 +232,7 @@ export function buildOverviewStats({
183
232
  stats.push({ label: "Fwd P/E", value: formatPriceEarnings(forwardPE) });
184
233
  }
185
234
  if (fundamentals?.eps != null) {
186
- stats.push({ label: "EPS", value: formatReportedMoney(fundamentals.eps, fundamentalsEpsCurrency({ fundamentals, financialCurrency }), true) });
235
+ stats.push({ label: "EPS", value: formatReportedMoney(fundamentals.eps, fundamentalsEpsCurrency({ fundamentals, financialCurrency, quote }), true) });
187
236
  }
188
237
  if (fundamentals?.pegRatio != null) {
189
238
  stats.push({ label: "PEG", value: formatPriceEarnings(fundamentals.pegRatio, 2) });
@@ -239,6 +288,8 @@ export function buildOverviewStats({
239
288
  if (fundamentals?.freeCashFlow != null) {
240
289
  stats.push({ label: "FCF", value: money(fundamentals.freeCashFlow) });
241
290
  }
291
+ const runwayField = runwayStat(runway);
292
+ if (runwayField) stats.push(runwayField);
242
293
  if (fundamentals?.operatingMargin != null) {
243
294
  stats.push({ label: "Op Margin", value: formatLevelPercent(fundamentals.operatingMargin) });
244
295
  }
@@ -255,7 +306,10 @@ export function buildOverviewStats({
255
306
  // At the regular session price, as the market cap above it is, with the check moved beside it.
256
307
  const priced = atRegularSessionPrice({ quote, fundamentals }).fundamentals;
257
308
  const enterpriseValue = reportedEnterpriseValue(priced);
258
- if (fundamentals?.unavailableFields?.includes("enterpriseValue")) {
309
+ // At or below zero, N/M as a P/E over a loss reads, with why in the space a stat has; valuation gives the full reason.
310
+ if (enterpriseValueNotMeaningful(priced)) {
311
+ stats.push({ label: "EV", value: formatPriceEarnings(NOT_MEANINGFUL), detail: ["cash > cap + debt", "cash > cap"] });
312
+ } else if (fundamentals?.unavailableFields?.includes("enterpriseValue")) {
259
313
  stats.push({ label: "EV", value: "—" });
260
314
  } else if (enterpriseValue != null) {
261
315
  // More than 5% from market cap + debt - cash: the provider's, with the computed figure where it fits.
@@ -264,7 +318,8 @@ export function buildOverviewStats({
264
318
  stats.push({
265
319
  label: "EV",
266
320
  value: formatCompactCurrency(enterpriseValue, quoteCurrency),
267
- detail: computed ? [`provider vs ${computed}`, "provider"] : undefined,
321
+ // An insurer's: its investment book is not netted as cash.
322
+ detail: computed ? [`provider vs ${computed}`, "provider"] : check?.investmentsKept ? ["investments in", "inv. in"] : undefined,
268
323
  });
269
324
  }
270
325
  if (finite(fundamentals?.beta)) {
@@ -1,4 +1,6 @@
1
1
  import { PerpEquityRow } from "../../perps/equity-row";
2
+ import { PerpMarketsSection } from "../../perps/markets-section";
3
+ import { perpetualListing } from "../../../../tickers/perpetual-listing";
2
4
  import { useCallback } from "react";
3
5
  import type { TickerResearchTabProps } from "../../../../types/plugin";
4
6
  import {
@@ -46,7 +48,13 @@ export function OverviewResearchTab({ width, height, focused }: TickerResearchTa
46
48
  onOpenChart={paneId && !lockedToOneTab ? openChart : undefined}
47
49
  onOpenFunction={openFunction}
48
50
  dividend={dividend}
49
- perpetuals={ticker ? <PerpEquityRow symbol={ticker.metadata.ticker} exchange={ticker.metadata.exchange} instrumentType={financials?.quote?.instrumentType ?? ticker.metadata.assetCategory} /> : undefined}
51
+ perpetuals={ticker ? (contentWidth: number) => {
52
+ const instrumentType = financials?.quote?.instrumentType ?? ticker.metadata.assetCategory;
53
+ // A contract's own DES shows its funding and premium; a stock or a coin lists its markets across venues.
54
+ return perpetualListing(ticker.metadata.ticker, ticker.metadata.exchange)
55
+ ? <PerpEquityRow symbol={ticker.metadata.ticker} exchange={ticker.metadata.exchange} instrumentType={instrumentType} />
56
+ : <PerpMarketsSection symbol={ticker.metadata.ticker} exchange={ticker.metadata.exchange} instrumentType={instrumentType} quote={financials?.quote} width={contentWidth} />;
57
+ } : undefined}
50
58
  />
51
59
  );
52
60
  }
@@ -6,13 +6,13 @@ import { mayBeUsEquityOrFundTicker } from "../../../utils/sec";
6
6
  import { ResearchTradeActions, researchTradeMatches, useResearchTrading } from "../shared/research-trading";
7
7
  import { instrumentFromTicker } from "../../../market-data/request-types";
8
8
  import { useMemo, type ReactNode } from "react";
9
- import { EmptyState, PaneLinkMenu, SectionHeading, usePaneNoticeFooter } from "../../../components";
9
+ import { EmptyState, ExternalLinkText, PaneLinkMenu, SectionHeading, usePaneNoticeFooter } from "../../../components";
10
10
  import { CompositeChart, pricePointsToResolvedSeries } from "../../../components/chart/composite";
11
11
  import { CompanyLogo, resolveCompanyLogoSrc } from "../../../components/company-logo";
12
12
  import { bodyLineInk, FigureText, figureLineInk, useFigureCells } from "../../../components/ui/figure";
13
13
  import { PriceReturnStrip } from "../../../components/price-performance";
14
14
  import { t } from "../../../i18n";
15
- import { useFxRatesMap } from "../../../market-data/hooks";
15
+ import { useFxRateObservations } from "../../../market-data/hooks";
16
16
  import { formatMarketPriceWithCurrency, formatSignedMarketPrice, liveQuoteFormatOptions } from "../../../market-data/market/format";
17
17
  import { priceSeriesUnit } from "../../../market-data/market/index-level";
18
18
  import {
@@ -24,9 +24,9 @@ import {
24
24
  quoteSessionLabel,
25
25
  } from "../../../market-data/market/status";
26
26
  import { appendQuoteToPriceReturnHistory, buildPriceReturnFields } from "../../../market-data/performance";
27
- import { changeBasisLabel, changeBasisNote, quoteChangeBasis } from "../../../market-data/market/change-basis";
27
+ import { changeBasisLabel, changeBasisNote, quoteChangeBasis, quoteSettleText } from "../../../market-data/market/change-basis";
28
28
  import {
29
- fitFuturesContractLines, futuresContractLines, futuresSettleText, isFuturesInstrument, minorUnitPricePer,
29
+ fitFuturesContractLines, futuresContractLines, isFuturesInstrument, futuresPricePer, usdPerMmbtu, usdPerMmbtuText,
30
30
  type FuturesContractLine,
31
31
  } from "../../../market-data/futures-contract";
32
32
  import { useViewport } from "../../../react/input";
@@ -38,10 +38,11 @@ import type { TickerRecord } from "../../../types/ticker";
38
38
  import { Box, ScrollBox, Text, useUiCapabilities } from "../../../ui";
39
39
  import { publicTickerKey, resolveExchangeTimeZone } from "../../../utils/exchanges";
40
40
  import { convertCurrency, displayWidth, formatPercentRaw, truncateToDisplayWidth } from "../../../utils/format";
41
- import { enterpriseValueReconciliationNote } from "../../../utils/fundamentals";
41
+ import { appTtmRate, enterpriseValueReconciliationNote, ttmAtAppRate, ttmConversionNote } from "../../../utils/fundamentals";
42
42
  import { atRegularSessionPrice } from "../../../market-data/quotes/regular-session-valuation";
43
43
  import { zonedDateKey } from "../../../utils/zoned-date-time";
44
44
  import { sharesOutstandingInReceipts } from "../../../utils/depositary-receipt";
45
+ import { isReceiptSide, listingDepositaryPair } from "../../../market-data/depositary-pair";
45
46
  import {
46
47
  CompactRangeBar,
47
48
  FundamentalsGrid,
@@ -61,6 +62,9 @@ import { describeFundamentalMarketCap } from "../../../utils/market-capitalizati
61
62
  import { liveFiftyTwoWeekRange, liveMarketCapitalization } from "../../../market-data/quotes/live-valuation";
62
63
  import { instrumentTypeLabel } from "../../../tickers/instrument-kind";
63
64
  import { ClippedText } from "../../../components/ui/display";
65
+ import { safeExternalUrl } from "../../../utils/external-url";
66
+ import { cashRunway, SHORT_RUNWAY_HISTORY } from "../../../utils/cash-runway";
67
+ import { useOfferingNote } from "./financials/offerings";
64
68
 
65
69
  /** Cells between the Day and 52W ranges when they share a row. */
66
70
  const RANGE_PAIR_GAP = 4;
@@ -83,7 +87,8 @@ function contractField(line: FuturesContractLine): StatField {
83
87
  }
84
88
 
85
89
  interface OverviewTabProps {
86
- perpetuals?: ReactNode;
90
+ /** The contracts on the security, given the width of the overview's content. */
91
+ perpetuals?: ReactNode | ((contentWidth: number) => ReactNode);
87
92
  width?: number;
88
93
  /** The tab's height; a short one keeps fewer futures contract terms. */
89
94
  height?: number;
@@ -131,19 +136,34 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
131
136
  const futuresSymbol = quote?.symbol || ticker.metadata.ticker;
132
137
  const contractTerms = useFuturesContractTerms(isFuturesInstrument(futuresSymbol, instrumentType) ? futuresSymbol : null);
133
138
  const optionRow = useOptionContractRow(ticker);
134
- const exchangeRates = useFxRatesMap([
139
+ const fxObservations = useFxRateObservations([
135
140
  baseCurrency,
136
141
  ticker.metadata.currency,
137
142
  quote?.currency,
138
143
  capitalization?.currency,
144
+ // A converted TTM block is shown at the pane's own rate, the one `fx` reports.
145
+ fundamentals?.ttmConversion?.from,
146
+ fundamentals?.financialCurrency,
139
147
  ...ticker.metadata.positions.map((position) => position.currency),
140
148
  ]);
149
+ const exchangeRates = useMemo(
150
+ () => new Map([...fxObservations].map(([currency, observation]) => [currency, observation.rate])),
151
+ [fxObservations],
152
+ );
153
+ const ttmRate = appTtmRate(fundamentals, (currency) => fxObservations.get(currency));
154
+ const shownFundamentals = useMemo(
155
+ () => (fundamentals ? ttmAtAppRate(fundamentals, ttmRate) : fundamentals),
156
+ [fundamentals, ttmRate?.rate, ttmRate?.asOf],
157
+ );
141
158
  const quoteCurrency = quote?.currency || ticker.metadata.currency || baseCurrency;
142
159
  const toBase = (value: number, fromCurrency: string) =>
143
160
  convertCurrency(value, fromCurrency, baseCurrency, exchangeRates);
144
161
  const sector = ticker.metadata.sector ?? profile?.sector;
145
162
  const industry = ticker.metadata.industry ?? profile?.industry;
146
163
  const description = profile?.description?.trim();
164
+ // A description quoted from the fund's issuer or its exchange names where it is from.
165
+ const descriptionSource = description && profile?.descriptionSource?.publisher
166
+ && safeExternalUrl(profile.descriptionSource.url) ? profile.descriptionSource : null;
147
167
  const listingVenue = exchangeShortName(
148
168
  quote?.tradingExchangeName ?? quote?.listingExchangeName ?? quote?.exchangeName,
149
169
  quote?.listingExchangeFullName ?? quote?.fullExchangeName,
@@ -185,12 +205,21 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
185
205
  // A provider EV off market cap + debt - cash, or why a withdrawn one is unavailable, at the
186
206
  // regular session price the EV beside it is shown at.
187
207
  const enterpriseValueNote = enterpriseValueReconciliationNote(atRegularSessionPrice({ quote, fundamentals }).fundamentals);
208
+ // Months of cash, for a company that burns it, and an offering since its balance sheet that the cash is not in yet.
209
+ const runway = useMemo(() => financials ? cashRunway(financials) : null, [financials]);
210
+ const runwayOfferingNote = useOfferingNote(ticker.metadata.ticker, ticker.metadata.exchange, runway?.periodEnd ?? null, runway?.trailing?.kind === "months");
211
+ // A converted TTM block names what it was converted from, at the pane's rate and its time.
212
+ const ttmNote = [shownFundamentals?.revenue, shownFundamentals?.netIncome, shownFundamentals?.freeCashFlow].some((value) => value != null)
213
+ ? ttmConversionNote(shownFundamentals) : undefined;
188
214
  usePaneNoticeFooter({
189
215
  registrationId: "overview-notices",
190
216
  notices: [
191
217
  ...(!quote && financials ? [t("Current quote unavailable. Other research data is still available.")] : []),
218
+ ...(runwayOfferingNote ? [runwayOfferingNote] : []),
219
+ ...(runway?.trailingGap === "short-history" ? [`Runway TTM: ${SHORT_RUNWAY_HISTORY}.`] : []),
192
220
  ...(priceSeries.warning ? [priceSeries.warning] : []),
193
221
  ...(enterpriseValueNote ? [enterpriseValueNote] : []),
222
+ ...(ttmNote ? [ttmNote] : []),
194
223
  ...(capitalization?.provenance.kind === "fundamentals" && !capitalization.live
195
224
  ? [`Market cap: ${describeFundamentalMarketCap(capitalization.provenance)}.`] : []),
196
225
  ],
@@ -209,7 +238,7 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
209
238
  const extendedQuote = getExtendedSessionDisplay(quote);
210
239
  // A price in cents says what it is per (314.95¢/lb), and the move what it is measured from (vs Fri 16 Oct close).
211
240
  const quotePriceText = sessionQuote
212
- ? `${formatMarketPriceWithCurrency(sessionQuote.price, quote?.currency, moneyOptions)}${minorUnitPricePer(contractTerms, quote?.currency)}` : "";
241
+ ? `${formatMarketPriceWithCurrency(sessionQuote.price, quote?.currency, moneyOptions)}${futuresPricePer(contractTerms, quote?.currency)}` : "";
213
242
  // Nor a move: the close it ended on is where it stays.
214
243
  const quoteChangeText = sessionQuote && !delisted ? formatSignedMarketPrice(sessionQuote.change, moneyOptions) : "";
215
244
  const quotePercentText = sessionQuote && !delisted ? `(${formatPercentRaw(sessionQuote.changePercent)})` : "";
@@ -240,9 +269,18 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
240
269
  // The exchange settlement, dated by its session: a futures price is its latest trade.
241
270
  const settleLabel = t("Settle");
242
271
  const settleText = contractTerms
243
- ? truncateToDisplayWidth(futuresSettleText(contractTerms, quote),
272
+ ? truncateToDisplayWidth(quoteSettleText(quote, contractTerms),
244
273
  Math.max(1, quoteTextWidth - displayWidth(settleLabel) - 1))
245
274
  : "";
275
+ // European gas beside Henry Hub: "≈ $30.832/MMBtu at EUR/USD 1.1650", at the app's rate, a conversion that says so.
276
+ const inUsdLabel = t("In USD");
277
+ const gasCurrency = quote?.currency?.trim().toUpperCase() ?? "";
278
+ const gasUsdPerUnit = gasCurrency ? convertCurrency(1, gasCurrency, "USD", exchangeRates) : Number.NaN;
279
+ const gasInUsd = sessionQuote && gasCurrency ? usdPerMmbtu(sessionQuote.price, contractTerms, gasCurrency, gasUsdPerUnit) : null;
280
+ const inUsdText = gasInUsd != null
281
+ ? truncateToDisplayWidth(usdPerMmbtuText({ value: gasInUsd, currency: gasCurrency, usdPerUnit: gasUsdPerUnit }),
282
+ Math.max(1, quoteTextWidth - displayWidth(inUsdLabel) - 1))
283
+ : "";
246
284
  const quoteChangeCells = delisted ? 0 : figureCells(quoteChangeText, "sub") + 1 + figureCells(quotePercentText, "sub");
247
285
  const stackQuoteChange = quoteChangeCells > quoteTextWidth;
248
286
  const stackQuoteSummary = figureCells(quotePriceText) + 2 + quoteChangeCells > quoteTextWidth;
@@ -285,9 +323,10 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
285
323
  const optionFields = optionTarget?.isOptionTicker ? optionContractFields(optionTarget, optionRow, quoteCurrency) : [];
286
324
  const contractFields = futuresFields.length > 0 ? futuresFields : optionFields;
287
325
  const contractGridColumns = futuresFields.length > 0 ? contractColumns : textGridColumns(optionFields, contentWidth);
326
+ const depositaryPair = listingDepositaryPair(financials);
288
327
  const stats = buildOverviewStats({
289
328
  quote,
290
- fundamentals,
329
+ fundamentals: shownFundamentals,
291
330
  financialCurrency: financials?.financialCurrency,
292
331
  quoteCurrency,
293
332
  baseCurrency,
@@ -295,10 +334,12 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
295
334
  marketCapExchangeRates: exchangeRates,
296
335
  nextEarnings: financials?.nextEarnings,
297
336
  depositaryReceipt: sharesOutstandingInReceipts(quote, fundamentals, description),
337
+ depositaryPair: depositaryPair ? { pair: depositaryPair, receiptSide: isReceiptSide(financials) } : null,
298
338
  // Report and ex-dividend dates are the listing's calendar days.
299
339
  today: zonedDateKey(Date.now(), chartTimeZone ?? "America/New_York"),
300
340
  dividend,
301
341
  bond: fundFacts?.bond ?? null,
342
+ runway,
302
343
  });
303
344
  const profileFields = buildProfileFields({
304
345
  // The contract section names an option's type.
@@ -308,8 +349,10 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
308
349
  profile,
309
350
  isin: ticker.metadata.isin,
310
351
  });
352
+ // Bars and the quote are dated on the listing's clock.
311
353
  const performanceFields = buildPriceReturnFields(
312
354
  appendQuoteToPriceReturnHistory(financials?.priceHistory ?? [], historyQuote),
355
+ ticker.metadata.exchange || quote?.listingExchangeName || quote?.exchangeName || undefined,
313
356
  );
314
357
  const hasPerformance = performanceFields.some((field) => field.value != null || field.unavailableReason);
315
358
  const positionRows = buildPositionRows({
@@ -414,6 +457,12 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
414
457
  <Text fg={colors.text}>{settleText}</Text>
415
458
  </Box>
416
459
  )}
460
+ {inUsdText && (
461
+ <Box flexDirection="row" gap={1} minWidth={0} overflow="hidden">
462
+ <Text flexShrink={0} fg={colors.textDim}>{inUsdLabel}</Text>
463
+ <Text fg={colors.textDim}>{inUsdText}</Text>
464
+ </Box>
465
+ )}
417
466
  {metadataParts.length > 0 && (
418
467
  <Text fg={colors.textDim}>{metadataParts.join(" | ")}</Text>
419
468
  )}
@@ -431,7 +480,7 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
431
480
  )}
432
481
  </Box>
433
482
 
434
- {perpetuals && <PaneLinkMenu>{perpetuals}</PaneLinkMenu>}
483
+ {perpetuals && <PaneLinkMenu>{typeof perpetuals === "function" ? perpetuals(contentWidth) : perpetuals}</PaneLinkMenu>}
435
484
 
436
485
  {(hasDayRange || yearRange) && quote && (
437
486
  <Box flexDirection={rangeInline ? "row" : "column"} gap={rangeInline ? RANGE_PAIR_GAP : 0} width={nativePaneChrome ? undefined : contentWidth}>
@@ -553,6 +602,14 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
553
602
  <SectionHeading title={t("Description")} />
554
603
  {/* The desktop wraps it at the pane's own width, so it follows a resize to the pixel. */}
555
604
  <Text fg={colors.text} width={nativePaneChrome ? undefined : contentWidth} wrapMode="word" wrapText>{description}</Text>
605
+ {descriptionSource && (
606
+ <PaneLinkMenu>
607
+ <Box flexDirection="row" width={nativePaneChrome ? undefined : contentWidth}>
608
+ <Text flexShrink={0} fg={colors.textDim}>{`${t("Source")}: `}</Text>
609
+ <ExternalLinkText url={descriptionSource.url} label={descriptionSource.publisher} />
610
+ </Box>
611
+ </PaneLinkMenu>
612
+ )}
556
613
  </Box>
557
614
  )}
558
615
  </Box>
@@ -227,6 +227,17 @@ export function TickerResearchPane({ focused, width, height }: PaneProps) {
227
227
  );
228
228
 
229
229
  const visibleTabIdKey = allTabs.map((tab) => tab.id).join("\0");
230
+ // A function that opens DES on one of its tabs (ADR) stamps the tab on the instance (command-tab.ts):
231
+ // it is shown once it is there to show, and once per stamp, so a later choice in the pane stands.
232
+ const requestedTabId = paneInstance?.params?.tab ?? null;
233
+ const requestedTabAt = paneInstance?.params?.tabAt ?? "";
234
+ const [consumedTabAt, setConsumedTabAt] = usePaneStateValue<string>("commandTabAt", "");
235
+ useEffect(() => {
236
+ if (!requestedTabId || !requestedTabAt || requestedTabAt === consumedTabAt) return;
237
+ if (!allTabs.some((tab) => tab.id === requestedTabId)) return;
238
+ setConsumedTabAt(requestedTabAt);
239
+ setActiveTabId(requestedTabId);
240
+ }, [consumedTabAt, requestedTabAt, requestedTabId, setActiveTabId, setConsumedTabAt, visibleTabIdKey]);
230
241
  // A quote tick re-renders this pane; the tab strip only has to re-render
231
242
  // when a tab appears, disappears, or is renamed.
232
243
  const tabItemsKey = allTabs.map((tab) => `${tab.id}:${tab.name}`).join("\0");
@@ -1,6 +1,6 @@
1
1
  import type { PaneFooterSegment } from "../../../components/layout/pane/footer";
2
2
  import { t } from "../../../i18n";
3
- import { isQuoteStaleForCurrentSession } from "../../../market-data/quotes/freshness";
3
+ import { isQuoteStaleForCurrentSession, noPrintsTodaySince } from "../../../market-data/quotes/freshness";
4
4
  import { formatQuoteNavAsOf } from "../../../market-data/quotes/time";
5
5
  import { delistingLabel } from "../../../market-data/quotes/delisting";
6
6
  import type { Quote } from "../../../types/financials";
@@ -17,12 +17,17 @@ export function tickerQuoteFooterInfo(
17
17
  // A listing that no longer trades: its quote is its last trade, said once with its date.
18
18
  info.push({ id: "ticker-research-stale", parts: [{ text: delistingLabel(quote.delisting), tone: "warning" }] });
19
19
  } else if (isQuoteStaleForCurrentSession(quote)) {
20
- const status: PaneFooterSegment = { id: "ticker-research-stale", parts: [{ text: t("Stale quote"), tone: "warning" }] };
20
+ // In a session the calendar has open with nothing printed in it, the warning says since when.
21
+ const quiet = noPrintsTodaySince(quote) != null;
22
+ const status: PaneFooterSegment = {
23
+ id: "ticker-research-stale",
24
+ parts: [{ text: quiet ? t("No prints today") : t("Stale quote"), tone: "warning" }],
25
+ };
21
26
  const timestamp = new Date(quote!.lastUpdated);
22
27
  if (navAsOf) {
23
28
  status.parts.push({ text: navAsOf, tone: "muted" });
24
29
  } else if (width != null && quote!.lastUpdated > 0 && Number.isFinite(timestamp.getTime())) {
25
- const sourceTime = `${timestamp.toISOString().slice(0, 16).replace("T", " ")}Z`;
30
+ const sourceTime = `${quiet ? "since " : ""}${timestamp.toISOString().slice(0, 16).replace("T", " ")}Z`;
26
31
  const accessWidth = access ? displayWidth(access.parts.map((part) => part.text).join(" ")) + 1 : 0;
27
32
  // Keep the warning and the existing entitlement action intact in narrow panes.
28
33
  if (displayWidth(status.parts[0]!.text) + 1 + sourceTime.length + accessWidth <= width - 2) {
@@ -2,6 +2,9 @@ import type { TickerFinancials } from "../../../types/financials";
2
2
  import type { TickerResearchTabDef } from "../../../types/plugin";
3
3
  import { FinancialsResearchTab } from "./financials/pane";
4
4
  import { OverviewResearchTab } from "./overview/pane";
5
+ import { AdrPairResearchTab } from "./adr-pair/tab";
6
+ import { ADR_PAIR_TAB_ID } from "./adr-pair/model";
7
+ import { listingDepositaryPair } from "../../../market-data/depositary-pair";
5
8
 
6
9
  function hasStatementFinancials(financials: TickerFinancials | null | undefined): boolean {
7
10
  return (financials?.annualStatements.length ?? 0) > 0 || (financials?.quarterlyStatements.length ?? 0) > 0;
@@ -29,4 +32,12 @@ export const TICKER_RESEARCH_BUILTIN_TABS: TickerResearchTabDef[] = [
29
32
  component: FinancialsResearchTab,
30
33
  isVisible: ({ financials }) => hasStatementFinancials(financials),
31
34
  },
35
+ {
36
+ // Only a listing Gloom Cloud pairs with a receipt has it, so every other DES is unchanged.
37
+ id: ADR_PAIR_TAB_ID,
38
+ name: "ADR vs Home",
39
+ order: 21,
40
+ component: AdrPairResearchTab,
41
+ isVisible: ({ financials }) => !!listingDepositaryPair(financials),
42
+ },
32
43
  ];
@@ -12,7 +12,7 @@ import {
12
12
  } from "./model";
13
13
  import { abortable, abortError } from "../../../utils/async-deadline";
14
14
  import { errorMessage } from "../../../utils/errors";
15
- import { findListedExpiry, unlistedExpiryText } from "../../../utils/option-expiry";
15
+ import { expiredExpiryText, findListedExpiry, isLiveOptionExpiry, liveOptionExpiries, unlistedExpiryText } from "../../../utils/option-expiry";
16
16
  import { optionModelSpot } from "../options/model-spot";
17
17
 
18
18
  const DEFAULT_SURFACE_EXPIRY_LIMIT = 18;
@@ -217,8 +217,7 @@ export async function loadVolatilitySurface(
217
217
  catalogueError = initial.error?.message ?? null;
218
218
  catalogueReason = initial.error?.reasonCode;
219
219
  if (!chain) catalogueError ??= "Options expiry catalogue unavailable";
220
- catalogue = [...new Set((chain?.expirationDates ?? []).filter((expiration) =>
221
- Number.isFinite(expiration) && expiration > 0 && daysToExpiryFrom(expiration, now) > 0))].sort((a, b) => a - b);
220
+ catalogue = liveOptionExpiries(chain?.expirationDates ?? [], now, request.instrument.exchange);
222
221
  // A typed date is that day's UTC midnight; the catalogue's stamp for the
223
222
  // same expiry is matched by calendar date, as OMON matches it.
224
223
  const required = [...new Set([...(request.requiredExpiries ?? []), ...(request.expiries ?? [])]
@@ -227,8 +226,10 @@ export async function loadVolatilitySurface(
227
226
  const listed = new Set(catalogue);
228
227
  selected = [...new Set([...request.expiries ? [] : selectSurfaceExpiries(catalogue, limit, now),
229
228
  ...required.filter((expiration) => listed.has(expiration))])].sort((a, b) => a - b);
229
+ // An expiry whose last session has closed is named as expired, with the nearest live one to pick.
230
230
  requiredFailures = required.filter((expiration) => !listed.has(expiration)).map((expiration) => ({
231
- expiration, message: unlistedExpiryText(expiration, catalogue),
231
+ expiration, message: isLiveOptionExpiry(expiration, now, request.instrument.exchange) ? unlistedExpiryText(expiration, catalogue)
232
+ : expiredExpiryText(expiration, catalogue, now, { exchange: request.instrument.exchange }),
232
233
  }));
233
234
  if (chain && catalogue.length === 0) catalogueError ??= "No unexpired option expiries available";
234
235
  } catch (error) {
@@ -1,7 +1,8 @@
1
1
  import type { Quote } from "../../../types/financials";
2
2
  import type { HeadlessBundleSection, HeadlessPaneDefinition, HeadlessPaneFreshness, HeadlessPaneLoadArgs, HeadlessPaneRow } from "../../../types/plugin";
3
3
  import {
4
- expirationOptionSeconds, findListedExpiry, OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER, readOptionExpiration, unlistedExpiryText,
4
+ expirationOptionSeconds, expiredExpiryText, findListedExpiry, isLiveOptionExpiry, OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER,
5
+ readOptionExpiration, unlistedExpiryText,
5
6
  } from "../../../utils/option-expiry";
6
7
  import { DATE_OPTION_EXAMPLES } from "../../../utils/calendar-date";
7
8
  import { IMPLIED_VOL_WORDS, skewHeader } from "../iv-history/format";
@@ -181,10 +182,18 @@ export const volSurfaceHeadless: HeadlessPaneDefinition<"bundle"> = {
181
182
  limit: Number(args.options.limit), signal: ctx.signal,
182
183
  requiredExpiries: requested == null ? [] : [requested],
183
184
  }, createSurfaceDependencies(ctx.marketData, ctx.apiClient)));
185
+ // An expired --expiration names the flag that asks for the nearest live one.
186
+ const now = Date.now();
187
+ if (requested != null && !isLiveOptionExpiry(requested, now, instrument.exchange)) {
188
+ const message = expiredExpiryText(requested, snapshot.catalogue, now, { exchange: instrument.exchange, flag: "expiration" });
189
+ snapshot = { ...snapshot, failures: snapshot.failures.map((failure) => failure.expiration === requested ? { ...failure, message } : failure) };
190
+ }
184
191
  }
185
192
  const available = snapshot.expiries.some((expiry) => expiry.fit);
186
- const loadErrors = snapshot.failures.map((failure) => failure.expiration == null ? failure.message
187
- : `${expiryLabel(failure.expiration)}: ${failure.message}`);
193
+ // An expiry that failed as the whole surface did (no connection) is not listed again under its own date.
194
+ const surfaceWide = new Set(snapshot.failures.filter((failure) => failure.expiration == null).map((failure) => failure.message));
195
+ const loadErrors = snapshot.failures.filter((failure) => failure.expiration == null || !surfaceWide.has(failure.message))
196
+ .map((failure) => failure.expiration == null ? failure.message : `${expiryLabel(failure.expiration)}: ${failure.message}`);
188
197
  // A symbol with no option chain at all says what became of it when something did (FB is a fund now,
189
198
  // Meta trades as META) in place of the chain's own error; a chain without clean quotes is the symbol's own.
190
199
  const fate = !snapshot.stored && !available && snapshot.catalogue.length === 0
@@ -613,8 +613,10 @@ export function buildSurfaceGrid(snapshot: SurfaceSnapshot, options: SurfaceGrid
613
613
  : axis === "strike" ? coordinate : deltaNeutralStrike(targetForward, tenor.years, (k) => at(k)?.volatility ?? null);
614
614
  if (strike === null) return unavailable();
615
615
  if (axis === "delta" && coordinate !== 0) {
616
- let low = Math.min(...available.map((expiry) => expiry.points[0]!.logMoneyness));
617
- let high = Math.max(...available.map((expiry) => expiry.points.at(-1)!.logMoneyness));
616
+ // The quoted strikes against each expiry's forward as it is now, the one its smile is read on: a report's
617
+ // forward is rounded after the points were placed, and the stored log-moneyness would land past the quotes.
618
+ let low = Math.min(...available.map((expiry) => logForwardMoneyness(expiry.points[0]!.strike, expiry.forward!)!));
619
+ let high = Math.max(...available.map((expiry) => logForwardMoneyness(expiry.points.at(-1)!.strike, expiry.forward!)!));
618
620
  const delta = (k: number) => {
619
621
  const value = at(k);
620
622
  return value == null ? null : optionDelta({ spot: snapshot.spot, years: tenor.years,
@@ -1,3 +1,4 @@
1
+ import { PERIOD_BASE_MAX_GAP_DAYS, periodBaseDay } from "../../../market-data/market/period-return";
1
2
  import type { CloudFredObservationPayload, CloudFredSeriesInfoPayload } from "../../../api-client";
2
3
  import type { PricePoint } from "../../../types/financials";
3
4
  import { VOLATILITY_CURVE_INDICES, VOLATILITY_INDICES } from "../shared/volatility-indices";
@@ -354,21 +355,15 @@ export interface VolatilityCurveLookback {
354
355
  values: Partial<Record<string, number>>;
355
356
  }
356
357
 
357
- /** A week back is seven calendar days; a month back is the same day of the previous month, or its last day. */
358
+ /** A week back is seven calendar days; a month back is the same day of the previous month, or its last day (periodBaseDay). */
358
359
  export function volatilityLookbackDate(date: string, id: VolatilityLookbackId): string {
359
- if (id === "1W") return new Date(Date.parse(date) - 7 * DAY_MS).toISOString().slice(0, 10);
360
- const target = new Date(`${date}T00:00:00.000Z`);
361
- const day = target.getUTCDate();
362
- target.setUTCDate(1);
363
- target.setUTCMonth(target.getUTCMonth() - 1);
364
- target.setUTCDate(Math.min(day, new Date(Date.UTC(target.getUTCFullYear(), target.getUTCMonth() + 1, 0)).getUTCDate()));
365
- return target.toISOString().slice(0, 10);
360
+ return periodBaseDay(date, id);
366
361
  }
367
362
 
368
363
  /**
369
364
  * The curve a week and a month before its date, read from the same daily
370
365
  * histories and aligned the same way: the last date on or before the look-back
371
- * where the 30D and 3M both closed, else where two tenors did, within ten days.
366
+ * where the 30D and 3M both closed, else where two tenors did, within a market closure of it (PERIOD_BASE_MAX_GAP_DAYS).
372
367
  * A tenor without a close on that date is a gap, never a neighbouring day.
373
368
  */
374
369
  export function volatilityCurveLookbacks(data: Pick<VolatilityData, "curve" | "board" | "fred">): VolatilityCurveLookback[] {
@@ -382,7 +377,7 @@ export function volatilityCurveLookbacks(data: Pick<VolatilityData, "curve" | "b
382
377
  }));
383
378
  return (["1W", "1M"] as const).map((id) => {
384
379
  const target = volatilityLookbackDate(curve.date!, id);
385
- const floor = new Date(Date.parse(target) - 10 * DAY_MS).toISOString().slice(0, 10);
380
+ const floor = new Date(Date.parse(target) - PERIOD_BASE_MAX_GAP_DAYS * DAY_MS).toISOString().slice(0, 10);
386
381
  const counts = new Map<string, number>();
387
382
  for (const history of histories.values()) for (const day of history.keys()) {
388
383
  if (day >= floor && day <= target) counts.set(day, (counts.get(day) ?? 0) + 1);