gloomberb 0.16.4 → 0.16.6

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 (852) hide show
  1. package/README.md +14 -91
  2. package/package.json +5 -1
  3. package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
  4. package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
  5. package/src/account/billing.ts +57 -0
  6. package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
  7. package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
  8. package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
  9. package/src/account/session.ts +16 -0
  10. package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
  11. package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
  12. package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
  13. package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
  14. package/src/api-client/central-bank-rates.ts +6 -1
  15. package/src/api-client/chat.ts +26 -0
  16. package/src/api-client/credit-boards.ts +2 -0
  17. package/src/api-client/data.ts +73 -3
  18. package/src/api-client/earnings.ts +6 -0
  19. package/src/api-client/europe-energy.ts +106 -0
  20. package/src/api-client/futures-curve.ts +56 -0
  21. package/src/api-client/index.ts +13 -1
  22. package/src/api-client/market-discovery.ts +13 -1
  23. package/src/api-client/normalizers.ts +32 -0
  24. package/src/api-client/paths.ts +7 -0
  25. package/src/api-client/perps.ts +8 -0
  26. package/src/api-client/request.ts +9 -2
  27. package/src/api-client/research-activity.ts +15 -10
  28. package/src/api-client/socket.ts +29 -0
  29. package/src/api-client/themes.ts +22 -1
  30. package/src/api-client/types.ts +78 -2
  31. package/src/api-client/yield-curves.ts +8 -0
  32. package/src/app/global-shortcuts.ts +50 -2
  33. package/src/app/keybindings/actions.ts +12 -1
  34. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  35. package/src/app/pane-runtime/ticker-open-runtime.ts +16 -6
  36. package/src/app/runtime/desktop-deeplink.ts +10 -5
  37. package/src/app/runtime/startup.ts +1 -1
  38. package/src/app.tsx +6 -0
  39. package/src/architecture/core-builtin-allowlist.json +8 -26
  40. package/src/ask-gloom/pane-context.ts +114 -0
  41. package/src/ask-gloom/pane-request.ts +70 -0
  42. package/src/ask-gloom/pane-text.ts +201 -0
  43. package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
  44. package/src/capabilities/chart-series.ts +19 -2
  45. package/src/capabilities/factories.ts +1 -0
  46. package/src/cli/central-bank-events.ts +23 -0
  47. package/src/cli/command-options.ts +17 -5
  48. package/src/cli/commands/crypto-hints.ts +35 -2
  49. package/src/cli/commands/fred-series.ts +146 -0
  50. package/src/cli/commands/market.ts +501 -115
  51. package/src/cli/commands/news-hints.ts +62 -0
  52. package/src/cli/commands/news-search.ts +53 -0
  53. package/src/cli/commands/options-leaps.ts +5 -2
  54. package/src/cli/commands/overview.ts +132 -26
  55. package/src/cli/commands/remote.ts +2 -1
  56. package/src/cli/commands/search.ts +317 -13
  57. package/src/cli/commands/system.ts +55 -8
  58. package/src/cli/commands/ticker.ts +155 -18
  59. package/src/cli/context.ts +45 -14
  60. package/src/cli/desktop-pane-shot.ts +76 -7
  61. package/src/cli/earnings-calendar.ts +71 -0
  62. package/src/cli/errors.ts +7 -5
  63. package/src/cli/exit-codes.ts +8 -0
  64. package/src/cli/export-source.ts +58 -0
  65. package/src/cli/freshness.ts +18 -7
  66. package/src/cli/glossary.ts +483 -0
  67. package/src/cli/help.ts +10 -0
  68. package/src/cli/helpers.ts +2 -5
  69. package/src/cli/history-rows.ts +118 -7
  70. package/src/cli/index-roots.ts +7 -0
  71. package/src/cli/index.ts +29 -9
  72. package/src/cli/known-gaps.ts +84 -0
  73. package/src/cli/listing-arg.ts +551 -97
  74. package/src/cli/not-a-ticker.ts +24 -9
  75. package/src/cli/pane-functions/access-gate.ts +13 -2
  76. package/src/cli/pane-functions/capabilities.ts +4 -3
  77. package/src/cli/pane-functions/catalog.ts +214 -40
  78. package/src/cli/pane-functions/data.ts +42 -8
  79. package/src/cli/pane-functions/discovery.ts +1 -0
  80. package/src/cli/pane-functions/dom.ts +37 -8
  81. package/src/cli/pane-functions/freshness.ts +393 -49
  82. package/src/cli/pane-functions/function-help.ts +31 -15
  83. package/src/cli/pane-functions/headless.ts +98 -30
  84. package/src/cli/pane-functions/index.ts +101 -19
  85. package/src/cli/pane-functions/market-session.ts +22 -8
  86. package/src/cli/pane-functions/options.ts +71 -22
  87. package/src/cli/pane-functions/report-notices.ts +25 -7
  88. package/src/cli/pane-functions/report.ts +15 -8
  89. package/src/cli/pane-functions/resolver.ts +74 -19
  90. package/src/cli/pane-functions/screenshot.ts +250 -27
  91. package/src/cli/perpetual-contract.ts +60 -0
  92. package/src/cli/registry.ts +3 -1
  93. package/src/cli/report-tables.ts +26 -7
  94. package/src/cli/result.ts +45 -11
  95. package/src/cli/series-search.ts +111 -0
  96. package/src/cli/staged-tickers.ts +52 -0
  97. package/src/cli/symbol-args.ts +27 -0
  98. package/src/cli/symbol-list.ts +154 -0
  99. package/src/cli/symbol-rows.ts +154 -0
  100. package/src/cli/ticker-resolution.ts +311 -27
  101. package/src/cli/types.ts +5 -0
  102. package/src/components/chart/composite/axis-overlays.tsx +14 -3
  103. package/src/components/chart/composite/composite-chart.tsx +71 -11
  104. package/src/components/chart/composite/crosshair-readout.tsx +150 -0
  105. package/src/components/chart/composite/downsample.ts +1 -1
  106. package/src/components/chart/composite/format.ts +29 -0
  107. package/src/components/chart/composite/interactions.ts +9 -2
  108. package/src/components/chart/composite/legend.tsx +100 -33
  109. package/src/components/chart/composite/panel-bitmap.ts +70 -35
  110. package/src/components/chart/composite/panel-labels.ts +18 -17
  111. package/src/components/chart/composite/panel-series.ts +1 -0
  112. package/src/components/chart/composite/panel-surface.tsx +46 -21
  113. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  114. package/src/components/chart/composite/rasterizer.ts +50 -8
  115. package/src/components/chart/composite/scene.ts +2 -1
  116. package/src/components/chart/composite/time-scale.ts +26 -9
  117. package/src/components/chart/composite/types.ts +18 -0
  118. package/src/components/chart/composite/use-composite-viewport.ts +30 -2
  119. package/src/components/chart/native/raster/crosshair.ts +8 -3
  120. package/src/components/chart/native/raster/primitives.ts +85 -21
  121. package/src/components/chart/native/surface/manager.ts +33 -8
  122. package/src/components/chart/surface3d/chart.tsx +1 -1
  123. package/src/components/command-bar/action-runtime.ts +1 -1
  124. package/src/components/command-bar/commands/collection-list.ts +210 -0
  125. package/src/components/command-bar/commands/collection.ts +40 -1
  126. package/src/components/command-bar/commands/direct/index.ts +4 -0
  127. package/src/components/command-bar/commands/registry.ts +8 -0
  128. package/src/components/command-bar/panel/index.tsx +11 -3
  129. package/src/components/command-bar/panel/runtime.ts +3 -0
  130. package/src/components/command-bar/panel/types.ts +2 -0
  131. package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
  132. package/src/components/command-bar/routes/root/provider-search.ts +4 -3
  133. package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
  134. package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
  135. package/src/components/command-bar/routing/actions.ts +1 -1
  136. package/src/components/command-bar/workflow/tickers.ts +42 -17
  137. package/src/components/layout/detached-pane-shell.tsx +68 -39
  138. package/src/components/layout/floating-pane.tsx +10 -1
  139. package/src/components/layout/header.tsx +25 -5
  140. package/src/components/layout/missing-pane.tsx +3 -3
  141. package/src/components/layout/pane/capture-stamp.ts +41 -0
  142. package/src/components/layout/pane/capture-status.ts +12 -0
  143. package/src/components/layout/pane/content.tsx +7 -13
  144. package/src/components/layout/pane/footer/index.tsx +6 -2
  145. package/src/components/layout/pane/footer/keyboard.ts +3 -0
  146. package/src/components/layout/pane/footer/model.ts +41 -1
  147. package/src/components/layout/pane/header.tsx +50 -1
  148. package/src/components/layout/pane/index.tsx +21 -3
  149. package/src/components/layout/pane/sidebar.tsx +88 -21
  150. package/src/components/layout/shell/active-drag.ts +21 -5
  151. package/src/components/layout/shell/cursor-occlusion.ts +2 -1
  152. package/src/components/layout/shell/drag/index.ts +39 -9
  153. package/src/components/layout/shell/drag/live.ts +61 -51
  154. package/src/components/layout/shell/drag/runtime.ts +54 -12
  155. package/src/components/layout/shell/index.tsx +84 -65
  156. package/src/components/layout/shell/menu.ts +14 -1
  157. package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
  158. package/src/components/layout/shell/pane/actions.ts +32 -10
  159. package/src/components/layout/shell/pane/ask.ts +131 -0
  160. package/src/components/layout/shell/pane/capture.ts +162 -0
  161. package/src/components/layout/shell/pane/layers.tsx +218 -50
  162. package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
  163. package/src/components/layout/shell/shortcuts.ts +21 -4
  164. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
  165. package/src/components/markdown-text.tsx +62 -20
  166. package/src/components/metric-treemap/heat-surface.tsx +8 -1
  167. package/src/components/onboarding/account-step/form-panel.tsx +1 -1
  168. package/src/components/onboarding/account-step/index.tsx +1 -1
  169. package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
  170. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  171. package/src/components/onboarding/onboarding-keyboard.ts +1 -1
  172. package/src/components/onboarding/onboarding-wizard.tsx +2 -2
  173. package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
  174. package/src/components/onboarding/wizard-account.ts +2 -2
  175. package/src/components/pane-template-wizard.tsx +9 -1
  176. package/src/components/price-selector-dialog.tsx +11 -2
  177. package/src/components/reader/article-reader.tsx +642 -0
  178. package/src/components/reader/article-text.ts +527 -0
  179. package/src/components/sign-in-gate.tsx +3 -3
  180. package/src/components/ticker/list-table-view.tsx +43 -2
  181. package/src/components/ui/action-row.tsx +2 -1
  182. package/src/components/ui/button.tsx +7 -1
  183. package/src/components/ui/choice-dialog.tsx +6 -4
  184. package/src/components/ui/confirm-dialog.tsx +28 -18
  185. package/src/components/ui/data-table/index.tsx +18 -6
  186. package/src/components/ui/data-table/opentui/index.tsx +37 -6
  187. package/src/components/ui/data-table/types.ts +12 -0
  188. package/src/components/ui/dialog-actions.tsx +64 -0
  189. package/src/components/ui/display.tsx +17 -3
  190. package/src/components/ui/frame.tsx +35 -2
  191. package/src/components/ui/icon.tsx +6 -1
  192. package/src/components/ui/query-bar.tsx +10 -1
  193. package/src/components/ui/text-prompt-dialog.tsx +11 -9
  194. package/src/data/cached-query.ts +2 -0
  195. package/src/data/config/store/migrations.ts +7 -0
  196. package/src/data/config/store/normalize.ts +7 -2
  197. package/src/data/config/store/portfolio-as-of-column.ts +57 -0
  198. package/src/data/ticker-repository.ts +5 -0
  199. package/src/data/ticker-store.ts +15 -0
  200. package/src/docs/content.ts +215 -0
  201. package/src/docs/load.ts +139 -0
  202. package/src/docs/requests.ts +39 -0
  203. package/src/docs/snapshot.chunk.ts +8 -0
  204. package/src/docs/snapshot.json +7555 -0
  205. package/src/docs/topics.ts +216 -0
  206. package/src/i18n/es.ts +65 -5
  207. package/src/i18n/ja.ts +65 -5
  208. package/src/i18n/ko.ts +65 -5
  209. package/src/i18n/zh-cn.ts +65 -5
  210. package/src/i18n/zh-tw.ts +65 -5
  211. package/src/layout/desks.ts +1 -1
  212. package/src/layout/pane-manager/dock-tree.ts +18 -0
  213. package/src/layout/pane-manager/index.ts +1 -0
  214. package/src/layout-marketplace/gallery.tsx +1 -1
  215. package/src/market-data/coordinator/chart.ts +10 -4
  216. package/src/market-data/coordinator/index.ts +6 -3
  217. package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
  218. package/src/market-data/futures-contract.ts +151 -0
  219. package/src/market-data/hooks.tsx +10 -2
  220. package/src/market-data/market/format.ts +39 -21
  221. package/src/market-data/market/freshness.ts +84 -20
  222. package/src/market-data/market/session-close-note.ts +3 -2
  223. package/src/market-data/market/status.ts +19 -23
  224. package/src/market-data/published-apac-sessions.ts +23 -1
  225. package/src/market-data/quotes/contributions.ts +5 -0
  226. package/src/market-data/quotes/metadata.ts +19 -24
  227. package/src/market-data/quotes/resolution.ts +5 -0
  228. package/src/market-data/quotes/screener-live-quotes.ts +5 -4
  229. package/src/market-data/result-types.ts +2 -0
  230. package/src/notifications/app-notifier.ts +17 -1
  231. package/src/notifications/notification-log.ts +180 -0
  232. package/src/plugins/auto-update-node.ts +2 -2
  233. package/src/plugins/auto-update.ts +2 -2
  234. package/src/plugins/builtin/account-management/index.tsx +1 -0
  235. package/src/plugins/builtin/account-management/model.ts +1 -56
  236. package/src/plugins/builtin/account-management/pane.tsx +6 -4
  237. package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
  238. package/src/plugins/builtin/alerts/catalysts.ts +1 -1
  239. package/src/plugins/builtin/alerts/cli.ts +313 -47
  240. package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
  241. package/src/plugins/builtin/alerts/events.ts +23 -2
  242. package/src/plugins/builtin/alerts/focus.ts +27 -0
  243. package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
  244. package/src/plugins/builtin/alerts/history.ts +2 -0
  245. package/src/plugins/builtin/alerts/index.tsx +47 -11
  246. package/src/plugins/builtin/alerts/pane.tsx +27 -1
  247. package/src/plugins/builtin/alerts/research-builder.ts +8 -3
  248. package/src/plugins/builtin/alerts/research-rules.ts +18 -2
  249. package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
  250. package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
  251. package/src/plugins/builtin/alerts/scheduled.ts +254 -0
  252. package/src/plugins/builtin/alerts/targets.ts +92 -0
  253. package/src/plugins/builtin/analytics/index.tsx +8 -3
  254. package/src/plugins/builtin/analytics/risk-headless.ts +60 -27
  255. package/src/plugins/builtin/analytics/risk-math.ts +91 -27
  256. package/src/plugins/builtin/analytics/risk-model.ts +35 -5
  257. package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
  258. package/src/plugins/builtin/attention/headless.ts +1 -1
  259. package/src/plugins/builtin/attention/index.tsx +2 -0
  260. package/src/plugins/builtin/attention/pane.tsx +3 -1
  261. package/src/plugins/builtin/attention/series.ts +26 -0
  262. package/src/plugins/builtin/awards/headless.ts +88 -18
  263. package/src/plugins/builtin/awards/index.tsx +2 -0
  264. package/src/plugins/builtin/awards/model.ts +41 -1
  265. package/src/plugins/builtin/awards/pane.tsx +22 -13
  266. package/src/plugins/builtin/awards/series.ts +29 -0
  267. package/src/plugins/builtin/backtest/headless.ts +2 -2
  268. package/src/plugins/builtin/bond-calculator/model.ts +2 -1
  269. package/src/plugins/builtin/broker-manager/index.tsx +1 -0
  270. package/src/plugins/builtin/catalysts/headless.ts +1 -1
  271. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  272. package/src/plugins/builtin/cds/client.ts +49 -12
  273. package/src/plugins/builtin/cds/headless.ts +119 -19
  274. package/src/plugins/builtin/cds/index.tsx +3 -1
  275. package/src/plugins/builtin/cds/model.ts +214 -32
  276. package/src/plugins/builtin/cds/pane.tsx +58 -14
  277. package/src/plugins/builtin/cds/series.ts +19 -0
  278. package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
  279. package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
  280. package/src/plugins/builtin/central-bank-rates/index.tsx +3 -1
  281. package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
  282. package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
  283. package/src/plugins/builtin/central-bank-rates/series.ts +36 -0
  284. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +193 -255
  285. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
  286. package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
  287. package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
  288. package/src/plugins/builtin/chart-composer/headless-schema.ts +1 -1
  289. package/src/plugins/builtin/chart-composer/headless.ts +70 -5
  290. package/src/plugins/builtin/chart-composer/index.tsx +15 -3
  291. package/src/plugins/builtin/chart-composer/pane.tsx +81 -38
  292. package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
  293. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
  294. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
  295. package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
  296. package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
  297. package/src/plugins/builtin/chat/content/composer.tsx +5 -1
  298. package/src/plugins/builtin/chat/content/footer.tsx +12 -0
  299. package/src/plugins/builtin/chat/content/index.tsx +89 -5
  300. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
  301. package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
  302. package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
  303. package/src/plugins/builtin/chat/content/scroll.ts +127 -27
  304. package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
  305. package/src/plugins/builtin/chat/content/transcript.tsx +145 -78
  306. package/src/plugins/builtin/chat/content/types.ts +1 -0
  307. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  308. package/src/plugins/builtin/chat/controller/index.ts +123 -1
  309. package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
  310. package/src/plugins/builtin/chat/controller/messages.ts +7 -2
  311. package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
  312. package/src/plugins/builtin/chat/controller/send.ts +61 -1
  313. package/src/plugins/builtin/chat/controller/state.ts +8 -0
  314. package/src/plugins/builtin/chat/ghost-user.ts +20 -0
  315. package/src/plugins/builtin/chat/index.tsx +23 -5
  316. package/src/plugins/builtin/chat/layout.ts +78 -5
  317. package/src/plugins/builtin/chat/message/ai-badge.tsx +18 -0
  318. package/src/plugins/builtin/chat/message/desktop.tsx +55 -6
  319. package/src/plugins/builtin/chat/message/header.tsx +16 -4
  320. package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
  321. package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
  322. package/src/plugins/builtin/chat/message/render-state.ts +18 -2
  323. package/src/plugins/builtin/chat/message/terminal.tsx +43 -4
  324. package/src/plugins/builtin/chat/message/types.ts +12 -0
  325. package/src/plugins/builtin/chat/reactions.ts +197 -0
  326. package/src/plugins/builtin/chat/share/flow.tsx +87 -0
  327. package/src/plugins/builtin/chat/share/targets.ts +27 -0
  328. package/src/plugins/builtin/chat/status-widget.tsx +6 -3
  329. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +148 -27
  330. package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
  331. package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
  332. package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
  333. package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
  334. package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
  335. package/src/plugins/builtin/cloud/askg/model.ts +27 -8
  336. package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
  337. package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
  338. package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
  339. package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
  340. package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
  341. package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
  342. package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
  343. package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
  344. package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
  345. package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
  346. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
  347. package/src/plugins/builtin/cloud/plugin.tsx +19 -2
  348. package/src/plugins/builtin/cloud/team/model.ts +5 -0
  349. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  350. package/src/plugins/builtin/cloud/team/store.ts +8 -3
  351. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
  352. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
  353. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
  354. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
  355. package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
  356. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  357. package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
  358. package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
  359. package/src/plugins/builtin/company-attention/headless.ts +21 -7
  360. package/src/plugins/builtin/company-attention/index.tsx +2 -0
  361. package/src/plugins/builtin/company-attention/model.ts +26 -7
  362. package/src/plugins/builtin/company-attention/pane.tsx +12 -9
  363. package/src/plugins/builtin/company-attention/series.ts +52 -0
  364. package/src/plugins/builtin/company-kpis/headless.ts +97 -10
  365. package/src/plugins/builtin/company-kpis/model.ts +24 -2
  366. package/src/plugins/builtin/company-kpis/pane.tsx +17 -16
  367. package/src/plugins/builtin/composite-plugins.ts +19 -13
  368. package/src/plugins/builtin/connections/index.ts +1 -0
  369. package/src/plugins/builtin/cot/headless.ts +1 -1
  370. package/src/plugins/builtin/cot/index.tsx +3 -1
  371. package/src/plugins/builtin/cot/model.ts +40 -11
  372. package/src/plugins/builtin/cot/series.ts +27 -0
  373. package/src/plugins/builtin/cpi/headless.ts +3 -3
  374. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
  375. package/src/plugins/builtin/credit-boards/client.ts +6 -2
  376. package/src/plugins/builtin/credit-boards/headless.ts +108 -31
  377. package/src/plugins/builtin/credit-boards/index.tsx +2 -0
  378. package/src/plugins/builtin/credit-boards/model.ts +11 -1
  379. package/src/plugins/builtin/credit-boards/series.ts +66 -0
  380. package/src/plugins/builtin/credit-conditions/client.ts +12 -9
  381. package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
  382. package/src/plugins/builtin/credit-conditions/index.tsx +18 -9
  383. package/src/plugins/builtin/credit-conditions/model.ts +19 -11
  384. package/src/plugins/builtin/credit-conditions/series.ts +16 -0
  385. package/src/plugins/builtin/credit-documents/headless.ts +33 -3
  386. package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
  387. package/src/plugins/builtin/crypto-board/headless.ts +2 -3
  388. package/src/plugins/builtin/crypto-board/index.tsx +2 -0
  389. package/src/plugins/builtin/crypto-board/model.ts +12 -0
  390. package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
  391. package/src/plugins/builtin/crypto-board/series.ts +48 -0
  392. package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
  393. package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
  394. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  395. package/src/plugins/builtin/debt-maturities/series.ts +45 -0
  396. package/src/plugins/builtin/dividend-yield/client.ts +3 -0
  397. package/src/plugins/builtin/dividend-yield/headless.ts +7 -4
  398. package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
  399. package/src/plugins/builtin/dividend-yield/pane.tsx +3 -1
  400. package/src/plugins/builtin/dividend-yield/series.ts +20 -0
  401. package/src/plugins/builtin/dividend-yield/types.ts +2 -0
  402. package/src/plugins/builtin/docs/blocks.tsx +181 -0
  403. package/src/plugins/builtin/docs/index.tsx +68 -0
  404. package/src/plugins/builtin/docs/pane.tsx +426 -0
  405. package/src/plugins/builtin/docs/targets.ts +72 -0
  406. package/src/plugins/builtin/docs/use-docs.ts +60 -0
  407. package/src/plugins/builtin/doe/headless.ts +12 -8
  408. package/src/plugins/builtin/doe/index.tsx +2 -0
  409. package/src/plugins/builtin/doe/series.ts +62 -0
  410. package/src/plugins/builtin/earnings/client.ts +3 -2
  411. package/src/plugins/builtin/earnings/format.ts +1 -5
  412. package/src/plugins/builtin/earnings/headless.ts +58 -6
  413. package/src/plugins/builtin/earnings/history-model.ts +15 -1
  414. package/src/plugins/builtin/earnings/history-table.ts +13 -2
  415. package/src/plugins/builtin/earnings/history.tsx +7 -3
  416. package/src/plugins/builtin/earnings/index.tsx +9 -0
  417. package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
  418. package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
  419. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
  420. package/src/plugins/builtin/econ/fred-catalog.ts +198 -0
  421. package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
  422. package/src/plugins/builtin/econ/index.tsx +2 -0
  423. package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
  424. package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
  425. package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
  426. package/src/plugins/builtin/equity-screener/headless.ts +3 -3
  427. package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
  428. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
  429. package/src/plugins/builtin/exposure/drivers.ts +13 -0
  430. package/src/plugins/builtin/exposure/headless.ts +205 -13
  431. package/src/plugins/builtin/exposure/holdings.ts +1 -1
  432. package/src/plugins/builtin/exposure/index.tsx +1 -0
  433. package/src/plugins/builtin/exposure/model.ts +23 -3
  434. package/src/plugins/builtin/exposure/pane.tsx +14 -12
  435. package/src/plugins/builtin/fear-greed/index.tsx +18 -10
  436. package/src/plugins/builtin/fear-greed/series.ts +52 -0
  437. package/src/plugins/builtin/futures/index.tsx +43 -3
  438. package/src/plugins/builtin/futures/model.ts +1 -1
  439. package/src/plugins/builtin/futures/returns.ts +1 -1
  440. package/src/plugins/builtin/futures/series.ts +13 -0
  441. package/src/plugins/builtin/futures/table.tsx +1 -1
  442. package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
  443. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  444. package/src/plugins/builtin/futures-curve/headless.ts +71 -10
  445. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  446. package/src/plugins/builtin/futures-curve/model.ts +66 -11
  447. package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
  448. package/src/plugins/builtin/fx-matrix/client.ts +63 -0
  449. package/src/plugins/builtin/fx-matrix/export.ts +2 -1
  450. package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
  451. package/src/plugins/builtin/fx-matrix/index.tsx +4 -4
  452. package/src/plugins/builtin/gpu/board.tsx +13 -10
  453. package/src/plugins/builtin/gpu/changes.tsx +4 -4
  454. package/src/plugins/builtin/gpu/client.ts +19 -1
  455. package/src/plugins/builtin/gpu/equities.tsx +14 -10
  456. package/src/plugins/builtin/gpu/headless.ts +58 -27
  457. package/src/plugins/builtin/gpu/history.tsx +3 -3
  458. package/src/plugins/builtin/gpu/index.tsx +2 -0
  459. package/src/plugins/builtin/gpu/model.ts +101 -16
  460. package/src/plugins/builtin/gpu/pane.tsx +28 -12
  461. package/src/plugins/builtin/gpu/series.ts +38 -0
  462. package/src/plugins/builtin/help/function-card.tsx +25 -6
  463. package/src/plugins/builtin/help/function-index.ts +2 -0
  464. package/src/plugins/builtin/help/index.tsx +31 -9
  465. package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
  466. package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
  467. package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
  468. package/src/plugins/builtin/holders/client.ts +22 -3
  469. package/src/plugins/builtin/holders/format.ts +18 -3
  470. package/src/plugins/builtin/holders/headless.ts +36 -133
  471. package/src/plugins/builtin/holders/pane.tsx +11 -4
  472. package/src/plugins/builtin/holders/report-header.ts +40 -5
  473. package/src/plugins/builtin/holders/report-rows.ts +240 -0
  474. package/src/plugins/builtin/insider/client.ts +35 -20
  475. package/src/plugins/builtin/insider/headless.ts +41 -11
  476. package/src/plugins/builtin/insider/index.tsx +26 -9
  477. package/src/plugins/builtin/insider/insider-data.ts +10 -0
  478. package/src/plugins/builtin/insider/issuer.ts +49 -0
  479. package/src/plugins/builtin/insider/model.ts +3 -0
  480. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
  481. package/src/plugins/builtin/iv-history/client.ts +20 -6
  482. package/src/plugins/builtin/iv-history/format.ts +9 -0
  483. package/src/plugins/builtin/iv-history/headless.ts +56 -21
  484. package/src/plugins/builtin/iv-history/index.tsx +2 -0
  485. package/src/plugins/builtin/iv-history/model.ts +143 -8
  486. package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
  487. package/src/plugins/builtin/iv-history/series.ts +29 -0
  488. package/src/plugins/builtin/jobs/headless.ts +26 -3
  489. package/src/plugins/builtin/jobs/index.tsx +3 -1
  490. package/src/plugins/builtin/jobs/series.ts +19 -0
  491. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  492. package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
  493. package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
  494. package/src/plugins/builtin/macro-day/client.ts +44 -3
  495. package/src/plugins/builtin/macro-day/headless.ts +13 -10
  496. package/src/plugins/builtin/macro-day/model.ts +56 -10
  497. package/src/plugins/builtin/macro-day/pane.tsx +30 -20
  498. package/src/plugins/builtin/market-heatmap/headless.ts +20 -5
  499. package/src/plugins/builtin/market-heatmap/index.tsx +6 -0
  500. package/src/plugins/builtin/market-heatmap/model.ts +19 -11
  501. package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
  502. package/src/plugins/builtin/market-movers/client.ts +7 -5
  503. package/src/plugins/builtin/market-movers/index.tsx +3 -2
  504. package/src/plugins/builtin/market-movers/model.ts +30 -0
  505. package/src/plugins/builtin/market-movers/screener.ts +31 -0
  506. package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
  507. package/src/plugins/builtin/market-valuation/index.tsx +3 -3
  508. package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
  509. package/src/plugins/builtin/members/headless.ts +8 -3
  510. package/src/plugins/builtin/members/model.ts +31 -3
  511. package/src/plugins/builtin/members/pane.tsx +6 -8
  512. package/src/plugins/builtin/mna/distress/headless.ts +4 -4
  513. package/src/plugins/builtin/mna/headless.ts +18 -6
  514. package/src/plugins/builtin/money-markets/headless.ts +5 -4
  515. package/src/plugins/builtin/money-markets/index.tsx +2 -0
  516. package/src/plugins/builtin/money-markets/series.ts +41 -0
  517. package/src/plugins/builtin/news/index.tsx +0 -2
  518. package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
  519. package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
  520. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
  521. package/src/plugins/builtin/notes/cli.ts +12 -7
  522. package/src/plugins/builtin/notes/index.tsx +1 -0
  523. package/src/plugins/builtin/options/index.tsx +3 -0
  524. package/src/plugins/builtin/options/view.tsx +1 -1
  525. package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
  526. package/src/plugins/builtin/options-positioning/client.ts +7 -3
  527. package/src/plugins/builtin/options-positioning/headless.ts +4 -3
  528. package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
  529. package/src/plugins/builtin/options-scenario/client.ts +2 -1
  530. package/src/plugins/builtin/options-scenario/headless.ts +1 -0
  531. package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
  532. package/src/plugins/builtin/perps/client.ts +90 -16
  533. package/src/plugins/builtin/perps/equity-row.tsx +52 -17
  534. package/src/plugins/builtin/perps/freshness.ts +66 -0
  535. package/src/plugins/builtin/perps/headless.ts +47 -32
  536. package/src/plugins/builtin/perps/index.tsx +23 -4
  537. package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
  538. package/src/plugins/builtin/perps/model.ts +20 -5
  539. package/src/plugins/builtin/perps/open-market.ts +15 -0
  540. package/src/plugins/builtin/perps/pane.tsx +76 -20
  541. package/src/plugins/builtin/perps/series.ts +76 -0
  542. package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
  543. package/src/plugins/builtin/plugin-marketplace/pane.tsx +73 -67
  544. package/src/plugins/builtin/plugin-module.ts +3 -0
  545. package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
  546. package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
  547. package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
  548. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +161 -0
  549. package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
  550. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +384 -74
  551. package/src/plugins/builtin/portfolio-list/cli/render.ts +437 -71
  552. package/src/plugins/builtin/portfolio-list/cli/shared.ts +21 -4
  553. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +121 -47
  554. package/src/plugins/builtin/portfolio-list/column-values.ts +104 -26
  555. package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
  556. package/src/plugins/builtin/portfolio-list/headless.ts +84 -18
  557. package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
  558. package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
  559. package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
  560. package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
  561. package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
  562. package/src/plugins/builtin/portfolio-list/pane/index.tsx +52 -9
  563. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +33 -11
  564. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
  565. package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
  566. package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
  567. package/src/plugins/builtin/portfolio-list/summary/totals.ts +9 -4
  568. package/src/plugins/builtin/portfolio-list/table.tsx +37 -7
  569. package/src/plugins/builtin/power/client.ts +16 -0
  570. package/src/plugins/builtin/power/evidence.ts +63 -10
  571. package/src/plugins/builtin/power/headless.ts +77 -9
  572. package/src/plugins/builtin/power/index.tsx +28 -3
  573. package/src/plugins/builtin/power/model.ts +73 -2
  574. package/src/plugins/builtin/power/pane.tsx +37 -9
  575. package/src/plugins/builtin/power/prices-client.ts +139 -0
  576. package/src/plugins/builtin/power/prices-headless.ts +137 -0
  577. package/src/plugins/builtin/power/prices-model.ts +103 -0
  578. package/src/plugins/builtin/power/prices.tsx +179 -0
  579. package/src/plugins/builtin/rate-path/headless.ts +46 -18
  580. package/src/plugins/builtin/realized-vol/headless.ts +5 -0
  581. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  582. package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
  583. package/src/plugins/builtin/research/event-model.ts +68 -24
  584. package/src/plugins/builtin/research/events-headless.ts +2 -1
  585. package/src/plugins/builtin/research/headless.ts +2 -1
  586. package/src/plugins/builtin/research/index.tsx +2 -0
  587. package/src/plugins/builtin/research-search/article.ts +65 -0
  588. package/src/plugins/builtin/research-search/document-view.tsx +33 -215
  589. package/src/plugins/builtin/research-search/model.ts +0 -9
  590. package/src/plugins/builtin/research-search/pane.tsx +41 -30
  591. package/src/plugins/builtin/research-search/snippet.ts +0 -29
  592. package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
  593. package/src/plugins/builtin/seasonality/client.ts +15 -7
  594. package/src/plugins/builtin/seasonality/headless.ts +36 -12
  595. package/src/plugins/builtin/seasonality/index.tsx +2 -2
  596. package/src/plugins/builtin/seasonality/model.ts +119 -0
  597. package/src/plugins/builtin/seasonality/pane.tsx +108 -37
  598. package/src/plugins/builtin/sec/headless.ts +25 -3
  599. package/src/plugins/builtin/sec/index.tsx +2 -1
  600. package/src/plugins/builtin/series-inventory.ts +93 -0
  601. package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
  602. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
  603. package/src/plugins/builtin/shared/command-tab.ts +30 -12
  604. package/src/plugins/builtin/shared/earnings-report.ts +55 -0
  605. package/src/plugins/builtin/shared/fred-points.ts +20 -0
  606. package/src/plugins/builtin/shared/free-preview.ts +47 -0
  607. package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
  608. package/src/plugins/builtin/shared/open-description.ts +29 -0
  609. package/src/plugins/builtin/shared/report-freshness.ts +12 -1
  610. package/src/plugins/builtin/shared/series-warning.ts +5 -0
  611. package/src/plugins/builtin/shared/volatility/options.ts +4 -1
  612. package/src/plugins/builtin/short-interest/headless.ts +1 -0
  613. package/src/plugins/builtin/short-interest/index.tsx +2 -0
  614. package/src/plugins/builtin/short-interest/series.ts +36 -0
  615. package/src/plugins/builtin/short-interest/watch-headless.ts +3 -2
  616. package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
  617. package/src/plugins/builtin/short-volume/headless.ts +2 -1
  618. package/src/plugins/builtin/short-volume/index.tsx +2 -0
  619. package/src/plugins/builtin/short-volume/series.ts +23 -0
  620. package/src/plugins/builtin/social-mentions/headless.ts +1 -1
  621. package/src/plugins/builtin/social-mentions/index.tsx +2 -0
  622. package/src/plugins/builtin/social-mentions/series.ts +23 -0
  623. package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
  624. package/src/plugins/builtin/supply-chain/headless.ts +43 -11
  625. package/src/plugins/builtin/supply-chain/model.ts +13 -0
  626. package/src/plugins/builtin/supply-chain/pane.tsx +8 -6
  627. package/src/plugins/builtin/themes/headless.ts +74 -10
  628. package/src/plugins/builtin/themes/model.ts +71 -4
  629. package/src/plugins/builtin/themes/pane.tsx +22 -5
  630. package/src/plugins/builtin/thirteenf/api.ts +1 -0
  631. package/src/plugins/builtin/thirteenf/data.ts +6 -4
  632. package/src/plugins/builtin/thirteenf/headless.ts +217 -36
  633. package/src/plugins/builtin/thirteenf/model.ts +39 -1
  634. package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
  635. package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
  636. package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
  637. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  638. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
  639. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
  640. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
  641. package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
  642. package/src/plugins/builtin/ticker-detail/headless.ts +86 -0
  643. package/src/plugins/builtin/ticker-detail/index.tsx +26 -11
  644. package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
  645. package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
  646. package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
  647. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
  648. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +49 -5
  649. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
  650. package/src/plugins/builtin/time-sales/headless.ts +2 -1
  651. package/src/plugins/builtin/time-sales/index.tsx +2 -1
  652. package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
  653. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  654. package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
  655. package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
  656. package/src/plugins/builtin/vol-surface/headless.ts +51 -17
  657. package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
  658. package/src/plugins/builtin/vol-surface/model.ts +39 -6
  659. package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
  660. package/src/plugins/builtin/vol-surface/stored.ts +63 -3
  661. package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
  662. package/src/plugins/builtin/volatility/index.tsx +2 -0
  663. package/src/plugins/builtin/volatility/series.ts +84 -0
  664. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
  665. package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
  666. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
  667. package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
  668. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
  669. package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
  670. package/src/plugins/builtin/world-venue-map/index.ts +2 -1
  671. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +24 -13
  672. package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
  673. package/src/plugins/builtin/world-venue-map/map.tsx +144 -13
  674. package/src/plugins/builtin/world-venue-map/model.ts +56 -19
  675. package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
  676. package/src/plugins/builtin/yield-curve/chart.ts +2 -2
  677. package/src/plugins/builtin/yield-curve/curves.ts +21 -8
  678. package/src/plugins/builtin/yield-curve/headless.ts +71 -18
  679. package/src/plugins/builtin/yield-curve/index.tsx +4 -2
  680. package/src/plugins/builtin/yield-curve/series.ts +86 -0
  681. package/src/plugins/catalog-browser.ts +2 -1
  682. package/src/plugins/installer.ts +2 -2
  683. package/src/plugins/loader.ts +15 -0
  684. package/src/plugins/manager-node.ts +1 -1
  685. package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
  686. package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +6 -6
  687. package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
  688. package/src/plugins/registry/host-actions.ts +11 -0
  689. package/src/plugins/registry/index.ts +89 -4
  690. package/src/portfolio/collection-name.ts +31 -0
  691. package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
  692. package/src/portfolio/position-value.ts +40 -0
  693. package/src/portfolio/valuation-basis.ts +79 -0
  694. package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
  695. package/src/public/time-series.ts +17 -0
  696. package/src/react/auto-refresh.ts +13 -3
  697. package/src/react/input.ts +33 -1
  698. package/src/react/key-repeat.ts +86 -0
  699. package/src/remote/app-host.tsx +20 -4
  700. package/src/remote/confirm-change.tsx +85 -0
  701. package/src/remote/controller-utils.ts +8 -1
  702. package/src/remote/controller.ts +144 -7
  703. package/src/remote/pane-screenshot.ts +47 -0
  704. package/src/remote/schema.ts +65 -2
  705. package/src/remote/types.ts +30 -0
  706. package/src/remote/watchlist.ts +306 -0
  707. package/src/renderers/browser/main.tsx +4 -3
  708. package/src/renderers/browser/research-entry.ts +4 -2
  709. package/src/renderers/cloudflare/worker.ts +1 -1
  710. package/src/renderers/dom/data-table/frozen-column.ts +3 -1
  711. package/src/renderers/dom/data-table/index.tsx +33 -6
  712. package/src/renderers/dom/data-table/row.tsx +30 -1
  713. package/src/renderers/dom/desktop/control-styles.ts +63 -1
  714. package/src/renderers/dom/desktop/controls.tsx +30 -23
  715. package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
  716. package/src/renderers/dom/desktop/icons.tsx +16 -0
  717. package/src/renderers/dom/dom-ui-host.tsx +3 -0
  718. package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
  719. package/src/renderers/dom/host/box.tsx +8 -0
  720. package/src/renderers/dom/host/chart-surface.tsx +33 -2
  721. package/src/renderers/dom/host/live-frame.ts +6 -2
  722. package/src/renderers/dom/host/overflow-fade.ts +14 -1
  723. package/src/renderers/dom/host/scroll-box.tsx +32 -0
  724. package/src/renderers/dom/host/size-observer.ts +41 -0
  725. package/src/renderers/dom/host/sticky-scroll.ts +128 -0
  726. package/src/renderers/dom/host/style.ts +1 -1
  727. package/src/renderers/dom/host/surface-3d.tsx +19 -7
  728. package/src/renderers/dom/host/surface-fit.ts +406 -0
  729. package/src/renderers/dom/host/text.tsx +1 -1
  730. package/src/renderers/dom/input-host.tsx +1 -0
  731. package/src/renderers/dom/styles.css +102 -5
  732. package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
  733. package/src/renderers/electrobun/bun/index.ts +3 -2
  734. package/src/renderers/electrobun/shared/protocol.ts +1 -1
  735. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +29 -2
  736. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +63 -20
  737. package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
  738. package/src/renderers/electrobun/view/main.tsx +5 -3
  739. package/src/renderers/electrobun/view/remote/asset-data-client.ts +2 -0
  740. package/src/renderers/opentui/chart-surface.tsx +1 -0
  741. package/src/renderers/opentui/frame-capture.ts +33 -0
  742. package/src/renderers/opentui/host.tsx +10 -13
  743. package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
  744. package/src/renderers/opentui/pane-image/glyphs.json +1 -0
  745. package/src/renderers/opentui/pane-image/index.ts +107 -0
  746. package/src/renderers/opentui/pane-image/raster.ts +428 -0
  747. package/src/renderers/opentui/start.tsx +3 -3
  748. package/src/renderers/opentui/test-utils.tsx +3 -0
  749. package/src/renderers/opentui/ui-host.tsx +29 -1
  750. package/src/series/capability.ts +75 -0
  751. package/src/series/csv.ts +160 -0
  752. package/src/series/files.ts +107 -0
  753. package/src/series/registry.ts +198 -0
  754. package/src/series/resolve.ts +108 -0
  755. package/src/series/standalone.ts +48 -0
  756. package/src/series/types.ts +153 -0
  757. package/src/series/validate.ts +171 -0
  758. package/src/shares/chat.ts +34 -0
  759. package/src/shares/dialog.tsx +295 -0
  760. package/src/shares/flow.tsx +56 -0
  761. package/src/shares/live.ts +14 -22
  762. package/src/shares/pane-image.ts +152 -0
  763. package/src/shares/personal-pane.ts +64 -0
  764. package/src/shares/portable-layout.ts +4 -2
  765. package/src/shares/prepare.ts +20 -0
  766. package/src/sources/gloomberb-cloud/index.ts +109 -10
  767. package/src/sources/gloomberb-cloud/normalizers.ts +3 -0
  768. package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
  769. package/src/sources/history-result.ts +1 -0
  770. package/src/sources/history-retention.ts +11 -0
  771. package/src/sources/listing-symbols.ts +4 -1
  772. package/src/sources/listing-target.ts +4 -0
  773. package/src/sources/provider-router/batches.ts +4 -1
  774. package/src/sources/provider-router/cache.ts +4 -2
  775. package/src/sources/provider-router/cached-routes.ts +1 -1
  776. package/src/sources/provider-router/financial-routes.ts +1 -0
  777. package/src/sources/provider-router/financials.ts +13 -0
  778. package/src/sources/provider-router/history.ts +43 -25
  779. package/src/sources/provider-router/index.ts +14 -0
  780. package/src/sources/provider-router/search.ts +1 -0
  781. package/src/state/hooks/inline-tickers.ts +49 -11
  782. package/src/sync/core-contributors.ts +1 -0
  783. package/src/test-support/shell-pane-keys.tsx +1 -0
  784. package/src/theme/theme-context.tsx +15 -1
  785. package/src/tickers/company-name.ts +75 -0
  786. package/src/tickers/instrument-kind.ts +34 -1
  787. package/src/tickers/listing-name.ts +34 -0
  788. package/src/tickers/listing-venues.ts +132 -0
  789. package/src/tickers/open-target.ts +13 -4
  790. package/src/tickers/perpetual-listing.ts +151 -0
  791. package/src/tickers/prediction-listing.ts +26 -0
  792. package/src/tickers/search/index.ts +72 -11
  793. package/src/tickers/search/ranking.ts +98 -20
  794. package/src/tickers/search/types.ts +7 -1
  795. package/src/tickers/ticker-changes.ts +213 -0
  796. package/src/tickers/us-listing.ts +34 -0
  797. package/src/time-series/economic.ts +2 -6
  798. package/src/time-series/hooks.ts +9 -0
  799. package/src/time-series/ice-credit.ts +39 -0
  800. package/src/time-series/resolve.ts +211 -29
  801. package/src/time-series/studies.ts +1 -0
  802. package/src/time-series/types.ts +12 -2
  803. package/src/time-series/use-chart-resolution.ts +32 -0
  804. package/src/types/config.ts +10 -2
  805. package/src/types/data-provider.ts +11 -0
  806. package/src/types/financials.ts +62 -1
  807. package/src/types/headless.ts +113 -0
  808. package/src/types/instrument.ts +4 -0
  809. package/src/types/plugin.ts +52 -2
  810. package/src/types/price-history.ts +7 -0
  811. package/src/types/ticker-changes.ts +26 -0
  812. package/src/types/ticker.ts +14 -0
  813. package/src/ui/context-menu.tsx +13 -1
  814. package/src/ui/host.tsx +57 -3
  815. package/src/ui/live-resize.ts +91 -0
  816. package/src/ui/live-stretch.ts +153 -0
  817. package/src/ui/measured-cells.ts +58 -0
  818. package/src/ui/sticky-scroll.ts +7 -0
  819. package/src/utils/basis-points.ts +17 -0
  820. package/src/utils/central-banks.ts +76 -0
  821. package/src/utils/cli-output.ts +131 -15
  822. package/src/utils/concurrency.ts +25 -0
  823. package/src/utils/crypto-pair.ts +20 -0
  824. package/src/utils/currency-pair.ts +19 -0
  825. package/src/utils/currency-units.ts +11 -0
  826. package/src/utils/datetime-format.ts +27 -6
  827. package/src/utils/decimal-comma.ts +19 -0
  828. package/src/utils/dom-screenshot-css.ts +265 -0
  829. package/src/utils/dom-screenshot-rasters.ts +276 -0
  830. package/src/utils/dom-screenshot.ts +439 -52
  831. package/src/utils/double-escape-close.ts +15 -1
  832. package/src/utils/exchange-rate-snapshot.ts +6 -2
  833. package/src/utils/exchanges.ts +143 -1
  834. package/src/utils/format.ts +35 -5
  835. package/src/utils/forward-dividend.ts +14 -0
  836. package/src/utils/fundamentals.ts +66 -0
  837. package/src/utils/futures-generic.ts +6 -12
  838. package/src/utils/fx-market-hours.ts +15 -5
  839. package/src/utils/fx-status.ts +6 -1
  840. package/src/utils/inline-content-tokenizer.ts +22 -3
  841. package/src/utils/market-capitalization.ts +8 -0
  842. package/src/utils/one-shot.ts +73 -0
  843. package/src/utils/options.ts +37 -8
  844. package/src/utils/price-history.ts +99 -42
  845. package/src/utils/sec-eps-basis.ts +24 -11
  846. package/src/utils/sec.ts +61 -7
  847. package/src/utils/utc-time.ts +63 -4
  848. package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
  849. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
  850. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
  851. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
  852. /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
@@ -1,5 +1,6 @@
1
1
  import { publicTickerBindingSymbol } from "../../../tickers/selection";
2
2
  import type { PluginModule } from "../plugin-module";
3
+ import { holdsActiveTicker } from "../../../shares/pane-image";
3
4
  import { TICKER_RESEARCH_PANE_ID } from "../../../types/config";
4
5
  import { normalizeTickerInput } from "../../../tickers/search";
5
6
  import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
@@ -7,9 +8,10 @@ import { FinancialAnalysisPane } from "./financials/pane";
7
8
  import { HistoricalPricesPane } from "./data-panes/historical-prices";
8
9
  import { ReturnsPane } from "./data-panes/returns-pane";
9
10
  import { TickerResearchPane } from "./pane";
11
+ import { futuresContractCache } from "./overview/futures-contract";
10
12
  import { TICKER_RESEARCH_BUILTIN_TABS } from "./research-tabs";
11
13
  import { QuoteMonitorPane } from "./quote-monitor";
12
- import { financialStatementsHeadless, historicalPricesHeadless, quoteComparisonHeadless } from "./headless";
14
+ import { financialStatementsHeadless, historicalPricesHeadless, quoteComparisonHeadless, returnsHeadless } from "./headless";
13
15
  import {
14
16
  buildQuoteMonitorSettingsDef,
15
17
  buildQuoteMonitorPaneTitle,
@@ -24,10 +26,12 @@ import {
24
26
 
25
27
  export const tickerDetailModule: PluginModule = {
26
28
  setup(ctx) {
29
+ futuresContractCache.attach(ctx.persistence);
27
30
  for (const tab of TICKER_RESEARCH_BUILTIN_TABS) {
28
31
  ctx.registerTickerResearchTab(tab);
29
32
  }
30
33
  },
34
+ dispose() { futuresContractCache.reset(); },
31
35
 
32
36
  panes: [
33
37
  {
@@ -37,6 +41,13 @@ export const tickerDetailModule: PluginModule = {
37
41
  component: TickerResearchPane,
38
42
  defaultPosition: "right",
39
43
  tickerFollower: true,
44
+ personalData: (context) => {
45
+ const settings = getTickerResearchPaneSettings(context.settings);
46
+ const tab = settings.hideTabs ? settings.lockedTabId : context.paneState.activeTabId;
47
+ // Notes and theses stay private even for a ticker the person does not hold.
48
+ if (tab === "notes") return "messages";
49
+ return tab === "thesis" || holdsActiveTicker(context) ? "holdings" : null;
50
+ },
40
51
  defaultMode: "floating",
41
52
  quickSettings: [LIVE_STREAMING_QUICK_SETTING],
42
53
  settings: (context) => withLiveStreamingSetting(
@@ -89,6 +100,7 @@ export const tickerDetailModule: PluginModule = {
89
100
  name: "Returns",
90
101
  icon: "R",
91
102
  component: ReturnsPane,
103
+ headless: returnsHeadless,
92
104
  defaultPosition: "right",
93
105
  tickerFollower: true,
94
106
  defaultMode: "floating",
@@ -162,16 +174,19 @@ export const tickerDetailModule: PluginModule = {
162
174
  : null;
163
175
  },
164
176
  },
165
- createTickerSurfacePaneTemplate({
166
- id: "returns-pane",
167
- paneId: "returns",
168
- label: "Returns",
169
- description: "Inspect interval and cumulative price returns over a selectable range and granularity.",
170
- keywords: ["returns", "return", "performance", "change", "interval", "granularity"],
171
- shortcut: "RETURN",
172
- publicShare: true,
173
- titlePrefix: "RETURN",
174
- }),
177
+ {
178
+ ...createTickerSurfacePaneTemplate({
179
+ id: "returns-pane",
180
+ paneId: "returns",
181
+ label: "Returns",
182
+ description: "Inspect interval and cumulative price returns over a selectable range and granularity.",
183
+ keywords: ["returns", "return", "performance", "change", "interval", "granularity"],
184
+ shortcut: "RETURN",
185
+ publicShare: true,
186
+ titlePrefix: "RETURN",
187
+ }),
188
+ headless: returnsHeadless,
189
+ },
175
190
  {
176
191
  ...createTickerSurfacePaneTemplate({
177
192
  id: "historical-prices-pane",
@@ -7,7 +7,7 @@ import type { Quote } from "../../../../types/financials";
7
7
  import { Box, Text } from "../../../../ui";
8
8
  import { displayWidth, formatNumber, padTo, truncateToDisplayWidth } from "../../../../utils/format";
9
9
  import type { OverviewFunctionLink, PositionTableRow, StatField } from "./types";
10
- import { portfolioPnlLabel } from "../../portfolio-list/position-metrics";
10
+ import { portfolioPnlLabel } from "../../../../portfolio/position-metrics";
11
11
 
12
12
  const STAT_COLUMN_GAP = 2;
13
13
  const STAT_LABEL_WIDTH = 12;
@@ -0,0 +1,31 @@
1
+ import { useCallback, useMemo } from "react";
2
+ import type { FuturesContractTermsPayload } from "../../../../api-client/futures-curve";
3
+ import { createPluginCache } from "../../../../data/plugin-cache";
4
+ import { loadFuturesContractTerms, validateFuturesContractTerms } from "../../../../market-data/futures-contract";
5
+ import { useAsyncResource, useAutoRefresh } from "../../../../public/react";
6
+ import { cachedCloudResource, loadCloudResource } from "../../shared/cloud-resource";
7
+
8
+ /** A day's settlement lands the morning after its session; the terms change only with a roll. */
9
+ const REFRESH_MS = 30 * 60_000;
10
+
11
+ export const futuresContractCache = createPluginCache<FuturesContractTermsPayload>({
12
+ kind: "futures-contract", source: "gloom-cloud", schemaVersion: 1,
13
+ policy: { staleMs: REFRESH_MS, expireMs: 7 * 24 * 60 * 60_000 },
14
+ });
15
+
16
+ /**
17
+ * A futures symbol's contract terms and latest confirmed settlement, beside
18
+ * the quote rather than in its way: the quote renders without them, a symbol
19
+ * the server has no terms for (or a failed request) leaves them out, and a
20
+ * cached copy shows at once while it is checked again.
21
+ */
22
+ export function useFuturesContractTerms(symbol: string | null): FuturesContractTermsPayload | null {
23
+ const loader = useCallback(async (force: boolean) => (await loadCloudResource(futuresContractCache, symbol!,
24
+ () => loadFuturesContractTerms(symbol!), { force, validate: validateFuturesContractTerms })).payload, [symbol]);
25
+ // Read once per symbol, not on every quote tick.
26
+ const cached = useMemo(() => symbol ? cachedCloudResource(futuresContractCache, symbol, validateFuturesContractTerms)?.payload ?? null : null, [symbol]);
27
+ const resource = useAsyncResource(symbol ? loader : null, { initialData: () => cached });
28
+ useAutoRefresh(resource.updatedAt, resource.load, { intervalMs: REFRESH_MS });
29
+ // A pane that moves to another symbol shows its cached copy while the request runs, so the block does not blink.
30
+ return symbol ? resource.data ?? (resource.loading ? cached : null) : null;
31
+ }
@@ -19,10 +19,10 @@ import {
19
19
  withCurrencyMinorDigits,
20
20
  } from "../../../../market-data/market/format";
21
21
  import type { OverviewFunctionLink, PositionTableRow, StatField } from "./types";
22
- import { getPortfolioPositionMetrics, getPortfolioQuoteDisplay, resolvePortfolioMarketValue, resolvePortfolioPositionPnl, portfolioPnlPercent, signedPositionDirection } from "../../portfolio-list/position-metrics";
22
+ import { getPortfolioPositionMetrics, getPortfolioQuoteDisplay, resolvePortfolioMarketValue, resolvePortfolioPositionPnl, portfolioPnlPercent, signedPositionDirection } from "../../../../portfolio/position-metrics";
23
23
  import { liveDividendYield, liveForwardPE, liveMarketCapitalization, liveTrailingPE } from "../../portfolio-list/live-valuation";
24
24
  import { formatReportedMoney } from "../../../../utils/reported-money";
25
- import { fundamentalsCurrency, reportedEnterpriseValue } from "../../../../utils/fundamentals";
25
+ import { fundamentalsCurrency, fundamentalsEpsCurrency, reportedEnterpriseValue } from "../../../../utils/fundamentals";
26
26
  import { formatShortDate } from "../../../../utils/datetime-format";
27
27
  import { safeExternalUrl } from "../../../../utils/external-url";
28
28
 
@@ -130,7 +130,7 @@ export function buildOverviewStats({
130
130
  stats.push({ label: "Fwd P/E", value: formatPriceEarnings(forwardPE) });
131
131
  }
132
132
  if (fundamentals?.eps != null) {
133
- stats.push({ label: "EPS", value: money(fundamentals.eps, true) });
133
+ stats.push({ label: "EPS", value: formatReportedMoney(fundamentals.eps, fundamentalsEpsCurrency({ fundamentals, financialCurrency }), true) });
134
134
  }
135
135
  if (fundamentals?.pegRatio != null) {
136
136
  stats.push({ label: "PEG", value: formatPriceEarnings(fundamentals.pegRatio, 2) });
@@ -16,7 +16,7 @@ import type { OverviewFunctionLink } from "./types";
16
16
  /** Registered by the chart composer, in the same plugin as this tab. */
17
17
  const CHART_TAB_ID = "chart";
18
18
 
19
- export function OverviewResearchTab({ width, focused }: TickerResearchTabProps) {
19
+ export function OverviewResearchTab({ width, height, focused }: TickerResearchTabProps) {
20
20
  const { ticker, financials } = usePaneTicker();
21
21
  const dispatch = useAppDispatch();
22
22
  const paneId = useOptionalPaneInstanceId();
@@ -37,6 +37,7 @@ export function OverviewResearchTab({ width, focused }: TickerResearchTabProps)
37
37
  return (
38
38
  <OverviewTab
39
39
  width={width}
40
+ height={height}
40
41
  focused={focused}
41
42
  ticker={ticker}
42
43
  financials={financials}
@@ -16,6 +16,7 @@ import {
16
16
  marketStateLabel,
17
17
  } from "../../../market-data/market/status";
18
18
  import { appendQuoteToPriceReturnHistory, buildPriceReturnFields } from "../../../market-data/performance";
19
+ import { fitFuturesContractLines, futuresContractLines, futuresSettleText, isFuturesInstrument, type FuturesContractLine } from "../../../market-data/futures-contract";
19
20
  import { useViewport } from "../../../react/input";
20
21
  import { useAppSelector } from "../../../state/app/context";
21
22
  import { colors, priceColor } from "../../../theme/colors";
@@ -36,10 +37,12 @@ import {
36
37
  rangeRowChrome,
37
38
  textGridColumns,
38
39
  } from "./overview/components";
40
+ import { useFuturesContractTerms } from "./overview/futures-contract";
39
41
  import { buildOverviewStats, buildPositionRows, buildProfileFields } from "./overview/model";
40
- import type { OverviewFunctionLink } from "./overview/types";
42
+ import type { OverviewFunctionLink, StatField } from "./overview/types";
41
43
  import { describeFundamentalMarketCap } from "../../../utils/market-capitalization";
42
44
  import { liveFiftyTwoWeekRange, liveMarketCapitalization } from "../portfolio-list/live-valuation";
45
+ import { instrumentTypeLabel } from "../../../tickers/instrument-kind";
43
46
 
44
47
  /** Cells between the Day and 52W ranges when they share a row. */
45
48
  const RANGE_PAIR_GAP = 4;
@@ -48,9 +51,24 @@ const RANGE_INLINE_MIN_TRACK = 10;
48
51
  /** Desktop px between the logo and the name and price beside it. */
49
52
  const LOGO_GAP_PX = 6;
50
53
 
54
+ /**
55
+ * Grid rows a futures Contract block may take. It sits above the chart, so a
56
+ * short pane keeps the chart in view by dropping the least useful terms.
57
+ */
58
+ function contractRowBudget(height: number | undefined): number {
59
+ if (height == null || height >= 32) return Number.POSITIVE_INFINITY;
60
+ return height >= 24 ? 3 : 2;
61
+ }
62
+
63
+ function contractField(line: FuturesContractLine): StatField {
64
+ return { label: line.label, value: line.value, ...(line.warning ? { valueColor: colors.warning } : {}) };
65
+ }
66
+
51
67
  interface OverviewTabProps {
52
68
  perpetuals?: ReactNode;
53
69
  width?: number;
70
+ /** The tab's height; a short one keeps fewer futures contract terms. */
71
+ height?: number;
54
72
  focused?: boolean;
55
73
  ticker: TickerRecord | null;
56
74
  financials: TickerFinancials | null;
@@ -65,7 +83,7 @@ export function OverviewTab(props: OverviewTabProps) {
65
83
  return <ResolvedOverviewTab {...props} ticker={props.ticker} />;
66
84
  }
67
85
 
68
- function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpenChart, onOpenFunction, perpetuals }: OverviewTabProps & { ticker: TickerRecord }) {
86
+ function ResolvedOverviewTab({ width, height, focused = false, ticker, financials, onOpenChart, onOpenFunction, perpetuals }: OverviewTabProps & { ticker: TickerRecord }) {
69
87
  const baseCurrency = useAppSelector((state) => state.config.baseCurrency);
70
88
  const { width: termWidth } = useViewport();
71
89
  const { fractionalViewport = false, nativePaneChrome, cellWidthPx = 8, cellHeightPx = 18, pixelRatio = 1 } = useUiCapabilities();
@@ -78,6 +96,9 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
78
96
  const instrumentType = quote?.instrumentType?.trim()
79
97
  || financials?.quoteMetadata?.instrumentType?.trim()
80
98
  || ticker.metadata.assetCategory;
99
+ // A futures symbol's settlement and contract terms load beside the quote, never in its way.
100
+ const futuresSymbol = quote?.symbol || ticker.metadata.ticker;
101
+ const contractTerms = useFuturesContractTerms(isFuturesInstrument(futuresSymbol, instrumentType) ? futuresSymbol : null);
81
102
  const exchangeRates = useFxRatesMap([
82
103
  baseCurrency,
83
104
  ticker.metadata.currency,
@@ -92,7 +113,7 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
92
113
  const industry = ticker.metadata.industry ?? profile?.industry;
93
114
  const description = profile?.description?.trim();
94
115
  const listingVenue = exchangeShortName(
95
- quote?.listingExchangeName ?? quote?.exchangeName,
116
+ quote?.tradingExchangeName ?? quote?.listingExchangeName ?? quote?.exchangeName,
96
117
  quote?.listingExchangeFullName ?? quote?.fullExchangeName,
97
118
  );
98
119
  const routingVenue = exchangeShortName(quote?.routingExchangeName, quote?.routingExchangeFullName);
@@ -163,6 +184,12 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
163
184
  const logoPx = quote ? logoBottomPx - logoTopPx : cellHeightPx * 2;
164
185
  const logoCells = hasLogo ? Math.ceil((logoPx + LOGO_GAP_PX) / cellWidthPx) : 0;
165
186
  const quoteTextWidth = Math.max(1, quoteSummaryWidth - logoCells);
187
+ // The exchange settlement, dated by its session: a futures price is its latest trade.
188
+ const settleLabel = t("Settle");
189
+ const settleText = contractTerms
190
+ ? truncateToDisplayWidth(futuresSettleText(contractTerms, quote),
191
+ Math.max(1, quoteTextWidth - displayWidth(settleLabel) - 1))
192
+ : "";
166
193
  const quoteChangeCells = figureCells(quoteChangeText, "sub") + 1 + figureCells(quotePercentText, "sub");
167
194
  const stackQuoteChange = quoteChangeCells > quoteTextWidth;
168
195
  const stackQuoteSummary = figureCells(quotePriceText) + 2 + quoteChangeCells > quoteTextWidth;
@@ -186,6 +213,10 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
186
213
  const rangeInline = hasDayRange && yearRange != null
187
214
  && rangeHalfWidth - rangeRowChrome(rangeLabelWidth, rangeEndpointCells) >= RANGE_INLINE_MIN_TRACK;
188
215
  const rangeWidth = rangeInline ? rangeHalfWidth : contentWidth;
216
+ const contractLines = contractTerms ? futuresContractLines(contractTerms, futuresSymbol) : [];
217
+ // Columns that keep every term whole; a narrow pane stacks them in one.
218
+ const contractColumns = textGridColumns(contractLines.map(contractField), contentWidth);
219
+ const contractFields = fitFuturesContractLines(contractLines, contractColumns * contractRowBudget(height)).map(contractField);
189
220
  const stats = buildOverviewStats({
190
221
  quote,
191
222
  fundamentals,
@@ -200,7 +231,7 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
200
231
  today: zonedDateKey(Date.now(), chartTimeZone ?? "America/New_York"),
201
232
  });
202
233
  const profileFields = buildProfileFields({
203
- instrumentType,
234
+ instrumentType: instrumentTypeLabel(instrumentType, quote?.name || ticker.metadata.name),
204
235
  sector,
205
236
  industry,
206
237
  profile,
@@ -277,6 +308,12 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
277
308
  </Text>
278
309
  </Box>
279
310
  )}
311
+ {settleText && (
312
+ <Box flexDirection="row" gap={1} minWidth={0} overflow="hidden">
313
+ <Text flexShrink={0} fg={colors.textDim}>{settleLabel}</Text>
314
+ <Text fg={colors.text}>{settleText}</Text>
315
+ </Box>
316
+ )}
280
317
  {metadataParts.length > 0 && (
281
318
  <Text fg={colors.textDim}>{metadataParts.join(" | ")}</Text>
282
319
  )}
@@ -288,7 +325,7 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
288
325
  )}
289
326
  </Box>
290
327
 
291
- {perpetuals}
328
+ {perpetuals && <PaneLinkMenu>{perpetuals}</PaneLinkMenu>}
292
329
 
293
330
  {(hasDayRange || yearRange) && quote && (
294
331
  <Box flexDirection={rangeInline ? "row" : "column"} gap={rangeInline ? RANGE_PAIR_GAP : 0} width={contentWidth}>
@@ -323,6 +360,13 @@ function ResolvedOverviewTab({ width, focused = false, ticker, financials, onOpe
323
360
  </Box>
324
361
  )}
325
362
 
363
+ {contractFields.length > 0 && (
364
+ <Box flexDirection="column">
365
+ <SectionHeading title={t("Contract")} />
366
+ <FundamentalsGrid fields={contractFields} width={contentWidth} columns={contractColumns} />
367
+ </Box>
368
+ )}
369
+
326
370
  {hasHistory && (
327
371
  <Box
328
372
  onMouseDown={onOpenChart
@@ -8,7 +8,7 @@ import type { TickerRecord } from "../../../../types/ticker";
8
8
  import type { ChartRequest, InstrumentRef } from "../../../../market-data/request-types";
9
9
  import { instrumentFromTicker, quoteSubscriptionTargetFromTicker } from "../../../../market-data/request-types";
10
10
  import { getSharedMarketDataCoordinator } from "../../../../market-data/coordinator";
11
- import { buildChartKey, buildQuoteKey } from "../../../../market-data/selectors";
11
+ import { buildChartKey, buildQuoteKey, resolveEntryData } from "../../../../market-data/selectors";
12
12
  import { DEFAULT_LIVE_CHART_REFRESH_INTERVAL_MS, useChartQueries } from "../../../../market-data/hooks";
13
13
  import { useAppSelector, usePaneInstance, usePaneTicker } from "../../../../state/app/context";
14
14
  import { useLiveQuoteEntries } from "../../../../state/hooks/quote-streaming";
@@ -229,6 +229,16 @@ export function QuoteMonitorPane({ paneId, focused, width, height }: PaneProps)
229
229
  const contentHeight = Math.max(3, height);
230
230
  const cardHeight = Math.max(nativePaneChrome ? 4 : 3, Math.floor(contentHeight / rows.length));
231
231
  const cardWidth = Math.max(1, Math.floor(contentWidth / columns));
232
+ // The stock's perpetual, under a card with room for it. A saved ticker often has no asset class, so the quote
233
+ // says whether it is a stock, as it does in DES.
234
+ const perpetuals = (entry: BoardEntry) => {
235
+ if (cardHeight < 8) return undefined;
236
+ const financials = financialsBySymbol.get(entry.symbol);
237
+ const quote = (entry.quoteKey ? resolveEntryData(quoteEntries.get(entry.quoteKey)) : null) ?? financials?.quote;
238
+ // Inside the card's padding: a cell each side here, about three on the desktop.
239
+ return <PerpEquityRow maxRows={1} symbol={entry.symbol} exchange={entry.ticker?.metadata.exchange} width={cardWidth - (nativePaneChrome ? 3 : 2)}
240
+ instrumentType={quote?.instrumentType ?? financials?.quoteMetadata?.instrumentType ?? entry.ticker?.metadata.assetCategory} />;
241
+ };
232
242
 
233
243
  if (nativePaneChrome) {
234
244
  const desktopColumns = gridColumns;
@@ -264,7 +274,7 @@ export function QuoteMonitorPane({ paneId, focused, width, height }: PaneProps)
264
274
  selected={showCursor && index === cursorIndex}
265
275
  onSelect={setCursorSymbol}
266
276
  onOpen={openTicker}
267
- perpetuals={cardHeight >= 8 ? <PerpEquityRow maxRows={1} symbol={entry.symbol} exchange={entry.ticker?.metadata.exchange} instrumentType={entry.ticker?.metadata.assetCategory} /> : undefined}
277
+ perpetuals={perpetuals(entry)}
268
278
  />
269
279
  ))}
270
280
  </Box>
@@ -299,7 +309,7 @@ export function QuoteMonitorPane({ paneId, focused, width, height }: PaneProps)
299
309
  selected={showCursor && rowIndex * columns + columnIndex === cursorIndex}
300
310
  onSelect={setCursorSymbol}
301
311
  onOpen={openTicker}
302
- perpetuals={cardHeight >= 8 ? <PerpEquityRow maxRows={1} symbol={entry.symbol} exchange={entry.ticker?.metadata.exchange} instrumentType={entry.ticker?.metadata.assetCategory} /> : undefined}
312
+ perpetuals={perpetuals(entry)}
303
313
  />
304
314
  ))}
305
315
  </Box>
@@ -14,9 +14,10 @@ function formattedColumns(rows: readonly HeadlessPaneRow[], formats: Record<stri
14
14
 
15
15
  export const timeSalesHeadless: HeadlessPaneDefinition<"bundle"> = {
16
16
  shape: "bundle", argument: { kind: "ticker", placeholder: "ticker", description: "US equity ticker." },
17
+ usListingsOnly: "Time and sales",
17
18
  options: [{ key: "limit", type: "integer", minimum: 1, maximum: 1000, defaultValue: 100, description: "Maximum recent prints in the report." }],
18
19
  discovery: { aliases: ["TAS", "QR"], dataRequirements: ["Gloom Cloud SIP trade and quote feed"],
19
- limitations: ["Bounded observed window, not a complete session", "SIP is delayed fifteen minutes without realtime entitlement", "Quote sizes are round lots", "No Level 2 or inferred aggressor side"] },
20
+ limitations: ["Bounded observed window, not a complete session.", "SIP is delayed fifteen minutes without realtime entitlement.", "Quote sizes are round lots.", "No Level 2 or inferred aggressor side."] },
20
21
  describe: (args) => `Time and sales ${args.argument ?? ""}`,
21
22
  async load(args, ctx) {
22
23
  const symbol = args.symbols[0] ?? (typeof args.argument === "string" ? args.argument : "");
@@ -11,7 +11,8 @@ export const timeSalesModule: PluginModule = {
11
11
  description: "Trade prints, observed VWAP and large prints.", keywords: ["tape", "trades", "sales", "prints", "tas"],
12
12
  shortcut: "TAS", viewKey: "TAS", settings: () => ({ tab: "trades" }) }), headless: timeSalesHeadless },
13
13
  { ...createTickerSurfacePaneTemplate({ id: "time-sales-qr", paneId: "time-sales", label: "Quote Recap",
14
- description: "NBBO history: bid and ask with sizes, venues and spread.", keywords: ["nbbo", "quotes", "bid", "ask", "recap", "qr"],
14
+ description: "NBBO history: bid and ask with sizes, venues and spread.",
15
+ keywords: ["nbbo", "quotes", "bid", "ask", "recap", "qr", "trades", "tick", "ticks", "tick data", "second", "seconds", "intraday", "milliseconds"],
15
16
  shortcut: "QR", viewKey: "QR", settings: () => ({ tab: "quotes" }) }), headless: timeSalesHeadless },
16
17
  ],
17
18
  };
@@ -18,6 +18,7 @@ import {
18
18
  formatAuctionRate,
19
19
  indirectPct,
20
20
  nextAuctionHistoryWindow,
21
+ rateQualifier,
21
22
  rateValue,
22
23
  stopOutVsAverageBp,
23
24
  visibleAuctions,
@@ -30,11 +31,24 @@ const formatPercent = (value: unknown) => value == null ? "-" : `${Number(value)
30
31
  const STOP_OUT_NOTE = "Stop-out vs avg is the high yield minus the average/median yield, in bp (bills: discount rates). "
31
32
  + "A true tail, the stop-out against the 1 pm when-issued yield, needs the when-issued yield, which the source does not carry.";
32
33
 
34
+ /** The rate as the table prints it; a TIPS or FRN row says what its number is (`2.653% real`, `4.0bp spread`). */
35
+ const rateCell = (value: unknown, row: Record<string, unknown>) => {
36
+ const text = formatAuctionRate(row as unknown as TreasuryAuction, value == null ? null : Number(value), "-");
37
+ const qualifier = value == null ? null : rateQualifier(row as unknown as TreasuryAuction);
38
+ return qualifier ? `${text} ${qualifier}` : text;
39
+ };
40
+
33
41
  const COLUMNS = [
34
42
  { key: "auctionDate", header: "Date" },
35
43
  { key: "secType", header: "Type" },
36
44
  { key: "securityTerm", header: "Term" },
37
- { key: "rate", header: "Rate", align: "right" as const, format: (value: unknown, row: Record<string, unknown>) => formatAuctionRate(row as unknown as TreasuryAuction, value == null ? null : Number(value), "-") },
45
+ {
46
+ key: "rate",
47
+ header: "Rate",
48
+ align: "right" as const,
49
+ format: (value: unknown, row: Record<string, unknown>) => formatAuctionRate(row as unknown as TreasuryAuction, value == null ? null : Number(value), "-"),
50
+ textFormat: rateCell,
51
+ },
38
52
  { key: "stopOutVsAvgBp", header: "Stop-out vs avg (bp)", align: "right" as const, format: (value: unknown) => value == null ? "-" : Number(value).toFixed(1) },
39
53
  { key: "bidToCoverRatio", header: "B/C", align: "right" as const, format: (value: unknown) => value == null ? "-" : Number(value).toFixed(2) },
40
54
  { key: "indirectPercent", header: "Indirect", align: "right" as const, format: formatPercent },
@@ -64,7 +78,7 @@ function createTreasuryAuctionsHeadless(
64
78
  ): HeadlessPaneDefinition<"rows"> {
65
79
  return {
66
80
  shape: "rows",
67
- freshness: { source: "US Treasury", status: "not-a-feed", basis: "auction results", observedKey: "auctionDate", oldest: null },
81
+ freshness: { source: "US Treasury", status: "not-a-feed", basis: "auction results", observedKey: "auctionDate", oldest: null, tradingDayMarket: "US" },
68
82
  argument: {
69
83
  kind: "free-text",
70
84
  placeholder: "search",
@@ -58,6 +58,7 @@ export const treasuryAuctionsModule: PluginModule = {
58
58
  defaultMode: "floating",
59
59
  defaultFloatingSize: { width: 104, height: 28 },
60
60
  tableExport: true,
61
+ reportFreshness: { source: "US Treasury", status: "not-a-feed", basis: "auction results" },
61
62
  settings: treasuryAuctionsSettings(),
62
63
  },
63
64
  ],
@@ -275,6 +275,14 @@ export function rateLabel(auction: TreasuryAuction): string {
275
275
  return FILTER_TYPES.bill.has(auction.secType) ? "Investment rate" : "High yield";
276
276
  }
277
277
 
278
+ /**
279
+ * What a rate needs beside its number to be read right: a TIPS yield is a real
280
+ * yield, and an FRN's figure is a spread over the 13-week bill index, not a yield.
281
+ */
282
+ export function rateQualifier(auction: TreasuryAuction): "real" | "spread" | null {
283
+ return auction.secType === "TIPS" ? "real" : auction.secType === "FRN" ? "spread" : null;
284
+ }
285
+
278
286
  /** FRN discount margins read in basis points; every other rate in percent. */
279
287
  export function formatAuctionRate(auction: TreasuryAuction, value: number | null, empty: string): string {
280
288
  if (value == null) return empty;
@@ -123,9 +123,15 @@ export function volSurfaceSemanticEvidence(input: VolSurfaceEvidenceInput): VolS
123
123
  };
124
124
  }
125
125
 
126
+ /** The evidence plus `ready: false` while an expiry is still loading, which holds a capture: a partial surface is no surface. */
127
+ export function volSurfaceEvidenceMetadata(input: VolSurfaceEvidenceInput): VolSurfaceEvidence & { ready: boolean } {
128
+ const evidence = volSurfaceSemanticEvidence(input);
129
+ return { ...evidence, ready: !evidence.loading };
130
+ }
131
+
126
132
  export function useVolSurfaceEvidence(input: VolSurfaceEvidenceInput): void {
127
133
  useRemoteUiNode({ role: "chart-data", label: "Rendered volatility observations",
128
- getMetadata: () => ({ ...volSurfaceSemanticEvidence(input) }) });
134
+ getMetadata: () => ({ ...volSurfaceEvidenceMetadata(input) }) });
129
135
  }
130
136
 
131
137
  /** Verify values and recompute counts so asserted readiness alone cannot certify a chart. */
@@ -1,10 +1,13 @@
1
- import type { HeadlessBundleSection, HeadlessPaneDefinition, HeadlessPaneFreshness, HeadlessPaneRow } from "../../../types/plugin";
1
+ import type { Quote } from "../../../types/financials";
2
+ import type { HeadlessBundleSection, HeadlessPaneDefinition, HeadlessPaneFreshness, HeadlessPaneLoadArgs, HeadlessPaneRow } from "../../../types/plugin";
2
3
  import {
3
- expirationOptionSeconds, OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER, readOptionExpiration,
4
+ expirationOptionSeconds, findListedExpiry, OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER, readOptionExpiration, unlistedExpiryText,
4
5
  } from "../../../utils/option-expiry";
6
+ import { skewHeader } from "../iv-history/format";
5
7
  import { formatStrikeLabel } from "../options/table";
6
8
  import { createSurfaceDependencies, loadVolatilitySurface } from "./client";
7
9
  import { buildSurfaceGrid, type SurfaceGridOptions, type SurfaceSettings, type SurfaceSnapshot } from "./model";
10
+ import { formatCaptureTime, loadDatedSurface, storedSurfaceDate, type DatedSurfaceSnapshot } from "./stored";
8
11
  import {
9
12
  expiryFeedFields, expiryLabel, formatIv, formatPrice, formatVolPoints, HIDDEN_SLOPE_TEXT, HIDDEN_YIELD_TEXT, selectSurfaceExpiry, surfaceForwardRow, surfaceSkewRow,
10
13
  surfaceSmileRows, surfaceTermRows, TERM_SLOPE_MIN_DAYS, type SurfaceForwardRow, type SurfaceSkewRow,
@@ -26,6 +29,17 @@ const SKEW_NOTES = [
26
29
  `Slope is the ATM IV change per year to the next listed expiry, in vol points; left out under ${TERM_SLOPE_MIN_DAYS} days to expiry, where it annualises a few hours of noise.`,
27
30
  ];
28
31
 
32
+ /**
33
+ * When and at what spot a stored close was taken, worded as the pane's footer
34
+ * words it, and the settings it cannot honour: it was fitted once, on mid
35
+ * quotes with recomputed IV.
36
+ */
37
+ function storedNotes(snapshot: DatedSurfaceSnapshot, options: HeadlessPaneLoadArgs["options"]): string[] {
38
+ const ignored = [options.ivSource !== "recomputed" && "--ivSource", options.priceSide !== "mid" && "--priceSide"].filter(Boolean);
39
+ return [`Stored close, spot ${formatPrice(snapshot.spot)}, captured ${formatCaptureTime(snapshot.stored!.capturedAt)} New York.`,
40
+ ...ignored.length ? [`A stored close is fitted on mid quotes with recomputed IV; ${ignored.join(" and ")} do${ignored.length === 1 ? "es" : ""} not apply.`] : []];
41
+ }
42
+
29
43
  const number = (value: unknown) => typeof value === "number" && Number.isFinite(value) ? value : null;
30
44
  const iv = (value: unknown) => formatIv(number(value));
31
45
  const price = (value: unknown) => formatPrice(number(value));
@@ -94,8 +108,9 @@ function skewSection(snapshot: SurfaceSnapshot): HeadlessBundleSection {
94
108
  return { title: "Skew", columns: [
95
109
  { key: "expiry", header: "Expiry" }, { key: "days", header: "Days", format: days },
96
110
  { key: "put25", header: "25D put IV", format: iv }, { key: "call25", header: "25D call IV", format: iv },
97
- { key: "riskReversal", header: "RR pts", format: gap }, { key: "butterfly", header: "BF pts", format: gap },
98
- { key: "moneynessSkew", header: "90/110 pts", format: (value, row) => typeof value === "number" ? points(value)
111
+ // Each difference names its sign: the risk reversal is call minus put, unlike HIVG and VCA's put-minus-call skew.
112
+ { key: "riskReversal", header: skewHeader("RR", "call-put"), format: gap }, { key: "butterfly", header: skewHeader("BF", "wings-ATM"), format: gap },
113
+ { key: "moneynessSkew", header: skewHeader("90/110", "90%-110%"), format: (value, row) => typeof value === "number" ? points(value)
99
114
  : (row as unknown as SurfaceSkewRow).moneynessGap ?? "--" },
100
115
  { key: "termSlope", header: "Slope pts/yr", format: (value, row) => typeof value === "number" ? points(value)
101
116
  : (row as unknown as SurfaceSkewRow).termSlopeHidden ? HIDDEN_SLOPE_TEXT : "--" },
@@ -115,6 +130,7 @@ function forwardsSection(snapshot: SurfaceSnapshot): HeadlessBundleSection {
115
130
 
116
131
  export const volSurfaceHeadless: HeadlessPaneDefinition<"bundle"> = {
117
132
  shape: "bundle", argument: { kind: "ticker", description: "Underlying ticker" },
133
+ usListingsOnly: "Options data",
118
134
  describe: (args) => `OVDV ${args.symbols[0] ?? ""}`,
119
135
  options: [
120
136
  { key: "tab", type: "enum", values: SURFACE_TABS.map((value) => ({ value })),
@@ -127,20 +143,36 @@ export const volSurfaceHeadless: HeadlessPaneDefinition<"bundle"> = {
127
143
  { key: "expiration", type: "string", placeholder: OPTION_EXPIRATION_PLACEHOLDER, example: "--expiration 2027-01-15 --tab smile",
128
144
  description: `Selected expiry, as ${OPTION_EXPIRATION_FORMAT}; the first at least four weeks out when omitted`,
129
145
  settingKey: "expiration", normalize: (value) => expirationOptionSeconds(value) },
146
+ { key: "date", type: "string", placeholder: "YYYY-MM-DD", example: "--date 2026-10-09 --tab skew",
147
+ description: "Stored close surface of that session instead of the live chain; a date with no capture lists the stored dates",
148
+ pluginState: { pluginId: "ticker-research", key: "historyDate" }, normalize: (value) => storedSurfaceDate(value) },
130
149
  ],
131
150
  async load(args, ctx) {
132
151
  const symbol = args.symbols[0]!;
133
- const instrument = await ctx.resolveInstrument?.(symbol) ?? { symbol };
134
- const quote = await ctx.marketData.getQuote(symbol, instrument.exchange);
135
- if (!(quote.price > 0) || !Number.isFinite(quote.price) || quote.stale) {
136
- return { sections: [], complete: false, unavailableSymbols: [symbol], errors: ["A current underlying price is required"] };
137
- }
138
152
  const requested = readOptionExpiration(args.options.expiration);
139
- const snapshot = await loadVolatilitySurface({ instrument, spot: quote.price, spotAsOf: quote.lastUpdated,
140
- settings: { ivSource: args.options.ivSource as SurfaceSettings["ivSource"], priceSide: args.options.priceSide as SurfaceSettings["priceSide"] },
141
- limit: Number(args.options.limit), signal: ctx.signal,
142
- requiredExpiries: requested == null ? [] : [requested],
143
- }, createSurfaceDependencies(ctx.marketData, ctx.apiClient));
153
+ const date = typeof args.options.date === "string" && args.options.date ? storedSurfaceDate(args.options.date) : null;
154
+ let snapshot: DatedSurfaceSnapshot;
155
+ let quote: Quote | null = null;
156
+ if (date) {
157
+ // A stored close needs no current price: it carries the spot it was fitted at.
158
+ snapshot = await loadDatedSurface(symbol, date, { signal: ctx.signal, api: ctx.apiClient });
159
+ // An expiry the capture does not have is named against the ones it has, as the live chain names its own.
160
+ if (requested != null && findListedExpiry(requested, snapshot.catalogue) == null) {
161
+ snapshot = { ...snapshot, failures: [...snapshot.failures, { expiration: requested, message: unlistedExpiryText(requested, snapshot.catalogue) }] };
162
+ }
163
+ } else {
164
+ const instrument = await ctx.resolveInstrument?.(symbol) ?? { symbol };
165
+ quote = await ctx.marketData.getQuote(symbol, instrument.exchange);
166
+ if (!(quote.price > 0) || !Number.isFinite(quote.price) || quote.stale) {
167
+ return { sections: [], complete: false, unavailableSymbols: [symbol], errors: ["A current underlying price is required"] };
168
+ }
169
+ snapshot = await loadVolatilitySurface({ instrument, spot: quote.price, spotAsOf: quote.lastUpdated,
170
+ settings: { ivSource: args.options.ivSource as SurfaceSettings["ivSource"], priceSide: args.options.priceSide as SurfaceSettings["priceSide"] },
171
+ limit: Number(args.options.limit), signal: ctx.signal,
172
+ requiredExpiries: requested == null ? [] : [requested],
173
+ }, createSurfaceDependencies(ctx.marketData, ctx.apiClient));
174
+ }
175
+ const stored = snapshot.stored ?? null;
144
176
  const axis = args.options.axis as SurfaceAxis;
145
177
  const tab = (SURFACE_TABS as readonly string[]).includes(String(args.options.tab)) ? args.options.tab as SurfaceTab : "surface";
146
178
  const available = snapshot.expiries.some((expiry) => expiry.fit);
@@ -166,9 +198,11 @@ export const volSurfaceHeadless: HeadlessPaneDefinition<"bundle"> = {
166
198
  unavailableSymbols: available ? [] : [symbol],
167
199
  errors: [...snapshot.failures.map((failure) => failure.expiration == null ? failure.message
168
200
  : `${expiryLabel(failure.expiration)}: ${failure.message}`), ...smile?.errors ?? []],
169
- ...(tab === "skew" ? { notes: SKEW_NOTES } : {}),
170
- ...(smile?.freshness ? { freshness: smile.freshness } : {}),
171
- metadata: { ...snapshot, underlyingQuote: quote, unit: "decimal annualized IV", methodology: "docs/research-data.md#shared-volatility-calculations" },
201
+ ...(stored || tab === "skew" ? { notes: [...stored ? storedNotes(snapshot, args.options) : [], ...tab === "skew" ? SKEW_NOTES : []] } : {}),
202
+ // A stored close is dated by its session, whichever view prints it.
203
+ ...(stored ? { freshness: { status: "not-a-feed" as const, basis: "stored close capture", asOf: stored.sessionDate } }
204
+ : smile?.freshness ? { freshness: smile.freshness } : {}),
205
+ metadata: { ...snapshot, ...quote ? { underlyingQuote: quote } : {}, unit: "decimal annualized IV", methodology: "docs/research-data.md#shared-volatility-calculations" },
172
206
  };
173
207
  },
174
208
  };