gloomberb 0.18.2 → 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 (954) 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/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -29,9 +29,10 @@ export interface NotesFilesIO {
29
29
  * Every note's key (its `.md` file name without the extension) and when it
30
30
  * was last written. A folder that does not exist yet, or a note gone before
31
31
  * it was looked at, lists nothing. Any other failure is logged and that part
32
- * left out, or, with `strict`, rejects.
32
+ * left out, or, with `strict`, rejects. A `skipped` callback receives an
33
+ * unreadable note instead of rejecting the whole listing.
33
34
  */
34
- listKeys(options?: { strict?: boolean }): Promise<Array<[string, number]>>;
35
+ listKeys(options?: NotesListOptions): Promise<Array<[string, number]>>;
35
36
  }
36
37
 
37
38
  const QUICK_NOTES_INDEX_FILE = "__quick-notes-index__.json";
@@ -108,8 +109,9 @@ export function diskNotesFilesIO(dataDir: string): NotesFilesIO {
108
109
  } catch (error) {
109
110
  // A note deleted since the folder was listed is simply gone.
110
111
  if ((error as NodeJS.ErrnoException)?.code === "ENOENT") continue;
111
- if (options?.strict) throw error;
112
+ if (options?.strict && !options.skipped) throw error;
112
113
  logFailure("notes.files", "Read when a note was last written failed")(error);
114
+ options?.skipped?.(name.slice(0, -3), error);
113
115
  }
114
116
  }
115
117
  return keys;
@@ -200,7 +202,16 @@ export function remoteNotesFilesIO(
200
202
  read: async (file) => await invoke("read", { dataDir, file }) as string | null,
201
203
  write: async (file, text) => { await invoke("write", { dataDir, file, text }); },
202
204
  delete: async (file) => { await invoke("delete", { dataDir, file }); },
203
- listKeys: async (options) => await invoke("listKeys", { dataDir, ...(options?.strict ? { strict: true } : {}) }) as Array<[string, number]>,
205
+ async listKeys(options) {
206
+ const result = await invoke("listKeys", {
207
+ dataDir, ...(options?.strict ? { strict: true } : {}),
208
+ ...(options?.skipped ? { reportSkipped: true } : {}),
209
+ });
210
+ if (!options?.skipped) return result as Array<[string, number]>;
211
+ const { keys, skipped } = result as { keys: Array<[string, number]>; skipped: Array<{ key: string; reason: string }> };
212
+ for (const { key, reason } of skipped) options.skipped(key, new Error(reason));
213
+ return keys;
214
+ },
204
215
  };
205
216
  }
206
217
 
@@ -245,7 +256,7 @@ export class NotesFiles implements NotesStore {
245
256
 
246
257
  /** Every stored note, ticker notes and quick notes alike, newest first. */
247
258
  async list(options: NotesListOptions = {}): Promise<NoteFileEntry[]> {
248
- const { entries } = await this.readEach(await this.io.listKeys({ strict: options.strict }), options.skipped);
259
+ const { entries } = await this.readEach(await this.io.listKeys(options), options.skipped);
249
260
  return entries.sort((left, right) => right.updatedAt - left.updatedAt);
250
261
  }
251
262
 
@@ -127,7 +127,7 @@ function DrugReportDetail({ record, width }: { record: DrugReport; width: number
127
127
  <KeyValueRow labelWidth={LABEL_WIDTH} label="Outcome" value={record.outcomes.length > 0 ? record.outcomes.join(", ") : record.outcome ?? "Not coded"} width={width} />
128
128
  {labelerText(record) ? <KeyValueRow labelWidth={LABEL_WIDTH} label="Labeler" value={labelerText(record)!} width={width} /> : null}
129
129
  {record.reporter ? <KeyValueRow labelWidth={LABEL_WIDTH} label="Reporter" value={record.reporter} width={width} /> : null}
130
- {record.country ? <KeyValueRow labelWidth={LABEL_WIDTH} label="Country" value={record.country} width={width} /> : null}
130
+ {record.country ? <KeyValueRow labelWidth={LABEL_WIDTH} label="Country" value={record.country} country={record.country} width={width} /> : null}
131
131
  <KeyValueRow labelWidth={LABEL_WIDTH} label="Report" value={record.id.slice("drug:".length)} width={width} />
132
132
  <Section title="Reactions" width={width}>
133
133
  <Prose text={record.reactions.join(", ") || "None coded."} width={width} figures={false} />
@@ -4,7 +4,7 @@ import { optionSpread } from "./market-reference";
4
4
 
5
5
  /**
6
6
  * What holding a contract costs in time value, read the same way by the OMON
7
- * columns and the LEAPS screen (`gloomberb options --leaps`):
7
+ * columns and the LEAPS screen (`gloom options --leaps`):
8
8
  *
9
9
  * intrinsic = max(0, spot - strike) for a call, max(0, strike - spot) for a put
10
10
  * extrinsic = midpoint - intrinsic, the midpoint of a two-sided quote
@@ -50,7 +50,7 @@ export function optionCarry(
50
50
 
51
51
  /**
52
52
  * Extrinsic per year net of financing and dividends, a fraction of spot per
53
- * year (`gloomberb options --leaps --columns carry-net`):
53
+ * year (`gloom options --leaps --columns carry-net`):
54
54
  *
55
55
  * call: (extrinsic - strike x rate x years + spot x dividend yield x years) / spot / years
56
56
  * put: (extrinsic + strike x rate x years - spot x dividend yield x years) / spot / years
@@ -4,7 +4,7 @@ import { buildOptionsKey, resolveEntryData } from "../../../market-data/selector
4
4
  import type { OptionsChain } from "../../../types/financials";
5
5
  import { normalizeSymbol, parsePublicTickerKey } from "../../../utils/exchanges";
6
6
  import { daysToExpiryFrom, volatilityTermSlope, type ExpectedMove } from "../shared/volatility";
7
- import { buildSurfaceExpiry, evaluateSurfaceSmile, type SurfaceExpiry } from "../vol-surface/model";
7
+ import { buildSurfaceExpiry, type SurfaceExpiry } from "../vol-surface/model";
8
8
  import type { YieldPoint } from "../yield-curve/treasury-data";
9
9
 
10
10
  export interface OptionsEnrichmentSelection {
@@ -97,8 +97,8 @@ export function optionsEnrichmentSelectionIssue(input: OptionsEnrichmentSelectio
97
97
 
98
98
  /**
99
99
  * Models kept between projections of one selection. The adjacent expiry does
100
- * not stream, so a live re-projection refits only the selected smile and reads
101
- * the adjacent ATM level off its existing fit at the current spot.
100
+ * not stream, so a live re-projection refits only the selected smile and keeps
101
+ * the adjacent fit, whose ATM-forward level does not move with the spot.
102
102
  */
103
103
  export interface OptionsEnrichmentCache {
104
104
  neighbour?: { chain: OptionsChain; curve: readonly YieldPoint[] | undefined; model: SurfaceExpiry };
@@ -134,17 +134,18 @@ export function projectOptionsEnrichment(input: OptionsEnrichmentProjection, cac
134
134
  else if (neighbourChain) {
135
135
  const cached = cache?.neighbour?.chain === neighbourChain && cache.neighbour.curve === input.curve
136
136
  ? cache.neighbour.model : null;
137
- const neighbour = cached ? { ...cached, atmIV: evaluateSurfaceSmile(cached, input.spot) }
138
- : buildSurfaceExpiry({ chain: neighbourChain, expiration: neighbourExpiration, spot: input.spot,
139
- curve: input.curve ?? [], now: input.now, source: input.neighbourEntry?.source });
137
+ const neighbour = cached ?? buildSurfaceExpiry({ chain: neighbourChain, expiration: neighbourExpiration, spot: input.spot,
138
+ curve: input.curve ?? [], now: input.now, source: input.neighbourEntry?.source });
140
139
  if (cache && !cached) cache.neighbour = { chain: neighbourChain, curve: input.curve, model: neighbour };
141
140
  result.rateAsOf = [...new Set([...result.rateAsOf, ...neighbour.rateAsOf])];
142
141
  result.warnings.push(...neighbour.warnings
143
142
  .filter((warning) => !(input.curveLoading && warning === "Treasury rate unavailable"))
144
143
  .map((warning) => `Adjacent expiry: ${warning}`));
145
- if (selected.atmIV != null && neighbour.atmIV != null) {
146
- Object.assign(result, optionsEnrichmentTermSlope({ years: selected.years, volatility: selected.atmIV },
147
- { years: neighbour.years, volatility: neighbour.atmIV }));
144
+ // The slope runs between the two expiries' IVs at their forwards, as OVDV's does, so a print
145
+ // against a closed session's chain does not tilt it.
146
+ if (selected.skew.atm != null && neighbour.skew.atm != null) {
147
+ Object.assign(result, optionsEnrichmentTermSlope({ years: selected.years, volatility: selected.skew.atm },
148
+ { years: neighbour.years, volatility: neighbour.skew.atm }));
148
149
  if (new Date(selected.asOf!).toISOString().slice(0, 10) !== new Date(neighbour.asOf!).toISOString().slice(0, 10)) {
149
150
  result.warnings.push("Term slope uses option observations from different dates");
150
151
  }
@@ -135,7 +135,7 @@ export const optionsModule: PluginModule = {
135
135
  paneId: "options",
136
136
  label: "Options",
137
137
  description: "Options chain for the selected ticker.",
138
- // Where a put seller picks the strike; OSA owns the exact put-selling phrases and ranks first on them.
138
+ // Where a put seller picks the strike; CSP and OSA own the exact put-selling phrases and rank first on them.
139
139
  keywords: ["options", "chain", "calls", "puts", "omon", "cash-secured puts", "selling puts", "short-put strikes", "csp strikes", "wheel strikes"],
140
140
  shortcut: "OMON",
141
141
  settings: (_symbol, _context, options) => {
@@ -1,3 +1,4 @@
1
+ import { getExtendedSessionDisplay, type ExtendedSession } from "../../../market-data/market/status";
1
2
  import { getPublishedUsEquitySession } from "../../../market-data/published-us-sessions";
2
3
  import type { OptionsChain, Quote } from "../../../types/financials";
3
4
  import { zonedWallClockToUtcMs } from "../../../utils/zoned-date-time";
@@ -82,10 +83,75 @@ export function formatSpotTime(time: number): string {
82
83
  return `${WEEKDAYS[date.getUTCDay()]} ${date.getUTCDate()} ${MONTHS[date.getUTCMonth()]} ${date.toISOString().slice(11, 16)} UTC`;
83
84
  }
84
85
 
85
- /** How a footer names the spot: `close Mon 12 Oct 20:00 UTC`, `pre-market Tue 13 Oct 12:21 UTC`, `last Tue 13 Oct 14:05 UTC`. */
86
- export function modelSpotLabel(spot: Pick<OptionModelSpot, "basis" | "session" | "observedAt">): string {
87
- const word = spot.basis === "close" ? "close" : spot.session ?? "last";
88
- return `${word} ${formatSpotTime(spot.observedAt)}`;
86
+ type SpotStampInput = Pick<OptionModelSpot, "basis" | "session" | "observedAt">;
87
+
88
+ /**
89
+ * The stamp every options pane puts beside the spot it priced a chain with
90
+ * (docs/research-data.md#greeks-spot-and-time): `close Tue 20 Oct` for the
91
+ * official close of the session the chain was quoted in, `pre-market Wed 21
92
+ * Oct 09:35 UTC` (`after hours`, `overnight`) for an extended-session print.
93
+ * Null for the regular session's latest price, which the pane's live or
94
+ * delayed status already dates.
95
+ */
96
+ export function modelSpotStamp(spot: SpotStampInput): string | null {
97
+ const dated = Number.isFinite(spot.observedAt);
98
+ if (spot.basis === "close") return dated ? `close ${formatCalendarDay(newYorkDate.format(spot.observedAt))}` : "close";
99
+ return spot.session && dated ? `${spot.session} ${formatSpotTime(spot.observedAt)}` : null;
100
+ }
101
+
102
+ /**
103
+ * The stamp's shorter forms, longest first, for a figure with less room
104
+ * (`StatItem.detailVariants`): `pre-market 09:35 UTC`, then `pre-market`;
105
+ * `close`. Empty when there is no stamp.
106
+ */
107
+ export function modelSpotStampVariants(spot: SpotStampInput): string[] {
108
+ if (!modelSpotStamp(spot)) return [];
109
+ if (spot.basis === "close") return ["close"];
110
+ return [`${spot.session} ${new Date(spot.observedAt).toISOString().slice(11, 16)} UTC`, spot.session!];
111
+ }
112
+
113
+ /** The stamp where a report or footer always dates the spot: `last Wed 21 Oct 14:05 UTC` for the regular session's price. */
114
+ export function modelSpotLabel(spot: SpotStampInput): string {
115
+ return modelSpotStamp(spot) ?? `last ${formatSpotTime(spot.observedAt)}`;
116
+ }
117
+
118
+ const HOUR_MS = 60 * 60_000;
119
+
120
+ /**
121
+ * A spot known only by its price and when it was observed, such as the one
122
+ * Gloom Cloud prices dealer gamma at: the session that time falls in on the
123
+ * listing's calendar. Pre-market from 04:00 New York to the open, after hours
124
+ * for four hours from the close, overnight between; a day the calendar does
125
+ * not know reads as the latest price.
126
+ */
127
+ export function observedModelSpot(price: number, observedAt: number, exchange?: string): OptionModelSpot {
128
+ const day = Number.isFinite(observedAt) ? getPublishedUsEquitySession(exchange || "NYSE", newYorkDate.format(observedAt)) : null;
129
+ const session: OptionModelSpot["session"] = day?.kind !== "session" ? null
130
+ : observedAt < day.open ? (observedAt >= day.open - 5.5 * HOUR_MS ? "pre-market" : "overnight")
131
+ : observedAt < day.close ? null
132
+ : observedAt < day.close + 4 * HOUR_MS ? "after hours" : "overnight";
133
+ return { price, observedAt, valuationTime: observedAt, basis: "last", session };
134
+ }
135
+
136
+ const EXTENDED_SESSION_WORDS: Record<ExtendedSession, NonNullable<OptionModelSpot["session"]>> = {
137
+ PRE: "pre-market", POST: "after hours", OVERNIGHT: "overnight",
138
+ };
139
+
140
+ /**
141
+ * The underlying's extended-session print beside a spot priced at the close,
142
+ * named by its session as the stamp names it: `pre-market 770.65`, `after
143
+ * hours mid 771.10`. Null when the spot is not the close, nothing traded
144
+ * outside the session, or the print is the spot.
145
+ */
146
+ export function modelSpotExtendedPrint(
147
+ quote: Quote | null | undefined,
148
+ spot: Pick<OptionModelSpot, "basis" | "price">,
149
+ format: (price: number) => string = formatModelSpotPrice,
150
+ ): string | null {
151
+ if (spot.basis !== "close") return null;
152
+ const print = getExtendedSessionDisplay(quote);
153
+ if (!print || !positive(print.price) || format(print.price) === format(spot.price)) return null;
154
+ return `${EXTENDED_SESSION_WORDS[print.session]}${print.mark ? " mid" : ""} ${format(print.price)}`;
89
155
  }
90
156
 
91
157
  /** A price to the cent, or to the tick it was quoted at below a dollar. */
@@ -5,9 +5,10 @@ import { colors, priceColor } from "../../../theme/colors";
5
5
  import { isPlainKey } from "../../../utils/keyboard";
6
6
  import { formatCompact, formatPercentRaw } from "../../../utils/format";
7
7
  import { formatMarketPrice, formatSignedMarketPrice, liveQuoteFormatOptions } from "../../../market-data/market/format";
8
+ import { getRegularSessionDisplay } from "../../../market-data/market/status";
8
9
  import { chainOptionContract, formatExpDate, optionContractName, resolveOptionsTarget } from "../../../utils/options";
9
10
  import {
10
- expiryIsoDate, findListedExpiry, formatDaysToExpiry, daysToExpiry, missingExpiryMessage, missingExpiryText, readOptionExpiration,
11
+ expiryIsoDate, findListedExpiry, formatDaysToExpiry, daysToExpiry, isLiveOptionExpiry, missingExpiryMessage, missingExpiryText, readOptionExpiration,
11
12
  } from "../../../utils/option-expiry";
12
13
  import { canonicalTickerKey } from "../../../utils/exchanges";
13
14
  import { isOptionsUnavailableError, listedOptionsAlternative, optionsUnavailableTitle } from "../../../market-data/options-alternatives";
@@ -68,7 +69,7 @@ import { signedPositionDirection } from "../../../portfolio/position-metrics";
68
69
  import { optionMarketReference } from "./market-reference";
69
70
  import { useOptionsEnrichment } from "./enrichment";
70
71
  import type { OptionsEnrichmentSnapshot } from "./enrichment-model";
71
- import { daysToExpiryFrom, optionMid, type OptionSide } from "../shared/volatility";
72
+ import { optionMid, type OptionSide } from "../shared/volatility";
72
73
  import type { TickerRecord } from "../../../types/ticker";
73
74
  import type { TickerFinancials } from "../../../types/financials";
74
75
  import type { IvStats } from "../iv-history/client";
@@ -76,7 +77,10 @@ import { useIvRank } from "../iv-history/rank";
76
77
  import { useOptionsSessionOpen, useThrottledValue } from "../shared/volatility/live-session";
77
78
  import { useRemoteUiNode } from "../../../remote/semantic-tree";
78
79
  import { optionCarry, optionCostOfSpot } from "./carry";
79
- import { formatModelSpotPrice, modelSpotLabel, optionModelSpot } from "./model-spot";
80
+ import {
81
+ formatModelSpotPrice, modelSpotExtendedPrint, modelSpotLabel, modelSpotStamp, modelSpotStampVariants, optionModelSpot,
82
+ type OptionModelSpot,
83
+ } from "./model-spot";
80
84
  import { chainOpenInterestAsOf, loadListedOpenInterest, openInterestAsOfLabel, statedOpenInterestAsOf } from "./open-interest-as-of";
81
85
  import { useAsyncResource } from "../../../react/async-resource";
82
86
  import {
@@ -113,13 +117,35 @@ function transientTicker(symbol: string, exchange: string, currency: string): Ti
113
117
  }
114
118
 
115
119
  /**
116
- * The underlying's price and day change: the level every strike is read
117
- * against. A stale quote stays on screen, muted, while the footer says why.
120
+ * The underlying's price: the level every strike is read against. A chain
121
+ * priced at a session's close or an extended-session print shows that spot
122
+ * with its stamp (`modelSpotStamp`), and any extended print after it named by
123
+ * its session; the regular session's live price shows its day change. A stale
124
+ * quote stays on screen, muted, while the footer says why.
118
125
  */
119
- function spotItem(underlying: TickerFinancials | null | undefined, assetCategory: string | undefined): StatItem {
126
+ function spotItem(
127
+ underlying: TickerFinancials | null | undefined,
128
+ assetCategory: string | undefined,
129
+ modelSpot: OptionModelSpot | null,
130
+ ): StatItem {
120
131
  const quote = underlying?.quote;
121
132
  if (!quote || !Number.isFinite(quote.price)) return { id: "spot", label: "Spot", value: "--" };
122
133
  const options = liveQuoteFormatOptions(quote, quote.currency, assetCategory, underlying?.quoteMetadata?.instrumentType);
134
+ const stamp = modelSpot ? modelSpotStamp(modelSpot) : null;
135
+ if (modelSpot && stamp) {
136
+ const move = modelSpot.basis === "close" ? getRegularSessionDisplay(quote)?.change : quote.change;
137
+ const extended = modelSpotExtendedPrint(quote, modelSpot, (price) => formatMarketPrice(price, options));
138
+ // The band keeps its columns: the extended print, then the stamp's day, give way first.
139
+ const shorter = modelSpotStampVariants(modelSpot);
140
+ return {
141
+ id: "spot",
142
+ label: "Spot",
143
+ value: formatMarketPrice(modelSpot.price, options),
144
+ detail: extended ? `${stamp} · ${extended}` : stamp,
145
+ detailVariants: extended ? [stamp, ...shorter] : shorter,
146
+ color: quote.stale ? colors.textDim : priceColor(Number.isFinite(move) ? move! : 0),
147
+ };
148
+ }
123
149
  const change = Number.isFinite(quote.change) ? quote.change : 0;
124
150
  return {
125
151
  id: "spot",
@@ -243,10 +269,10 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
243
269
  const strikeWindowText = strikeWindowValue(strikeWindow);
244
270
  const initialChainEntry = useOptionsQuery(baseRequest);
245
271
  const initialChain = useResolvedEntryValue(initialChainEntry);
246
- // A listing can still carry a date whose 16:00 ET close has passed. The chain
272
+ // A listing can still carry a date whose last session has closed. The chain
247
273
  // never opens there, nor on a saved date that has since passed: it takes the nearest live one.
248
274
  const now = Date.now();
249
- const liveExpiration = (expiration: number) => daysToExpiryFrom(expiration, now) > 0;
275
+ const liveExpiration = (expiration: number) => isLiveOptionExpiry(expiration, now, effectiveExchange);
250
276
  const listedExpirations = initialChain?.expirationDates ?? [];
251
277
  const openingExpirations = listedExpirations.some(liveExpiration) ? listedExpirations.filter(liveExpiration) : listedExpirations;
252
278
  const initialExpiration = openingExpirations.length === 0 ? undefined : openingExpirations.reduce((best, expiration) => (
@@ -295,10 +321,10 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
295
321
  const expirationDates = useMemo(() => {
296
322
  const listed = selectedExpirationMissing
297
323
  ? [...availableExpirations, selectedExpiration!].sort((left, right) => left - right) : availableExpirations;
298
- // A date that has ended has no contracts left to show; the strip leaves it out, unless every date has.
299
- const current = (expiration: number) => daysToExpiry(expiration, Date.now()) >= 0;
324
+ // A date whose last session has closed has no contracts left to show; the strip leaves it out, unless every date has.
325
+ const current = (expiration: number) => isLiveOptionExpiry(expiration, Date.now(), effectiveExchange);
300
326
  return listed.some(current) ? listed.filter((expiration) => expiration === selectedExpiration || current(expiration)) : listed;
301
- }, [availableExpirations, selectedExpiration, selectedExpirationMissing]);
327
+ }, [availableExpirations, effectiveExchange, selectedExpiration, selectedExpirationMissing]);
302
328
  // Keep the date strip stable while a mouse press focuses this pane. A new
303
329
  // tab list asks the web host to reveal the active tab and can move the date
304
330
  // being clicked before mouse-up, cancelling selection of an offscreen expiry.
@@ -418,7 +444,7 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
418
444
  const chainAsOfMs = asOfChain?.asOf ? Date.parse(asOfChain.asOf) : Number.NaN;
419
445
  const expiryAsOfMs = Number.isFinite(chainAsOfMs) ? chainAsOfMs : Date.now();
420
446
  const expiryDate = selectedExpiration == null ? "" : expiryIsoDate(selectedExpiration);
421
- const expiryDays = selectedExpiration == null ? "" : formatDaysToExpiry(selectedExpiration, expiryAsOfMs);
447
+ const expiryDays = selectedExpiration == null ? "" : formatDaysToExpiry(selectedExpiration, expiryAsOfMs, effectiveExchange);
422
448
  useRemoteUiNode(expiryDate && chain && !expirationUnavailable ? {
423
449
  role: "report-notice",
424
450
  label: "Expiry",
@@ -448,7 +474,7 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
448
474
  ...(chainDelay > 0 ? { delayMinutes: chainDelay } : {}),
449
475
  }),
450
476
  } : null);
451
- // A report of the pane (`gloomberb fn OMON`) says how many strikes it lists of how many the expiry has.
477
+ // A report of the pane (`gloom fn OMON`) says how many strikes it lists of how many the expiry has.
452
478
  useRemoteUiNode(strikeChain ? {
453
479
  role: "report-notice",
454
480
  label: "Strike window",
@@ -552,10 +578,10 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
552
578
  putGreeks: volatilities ? calculateOptionGreeks(put, "put", greeksSpot, dividendYield, volatilities) : undefined,
553
579
  callExtrinsicPerYear: call && volatilities ? optionCarry(call, "call", greeksSpot, volatilities.valuationTime)?.extrinsicPerYear ?? null : null,
554
580
  putExtrinsicPerYear: put && volatilities ? optionCarry(put, "put", greeksSpot, volatilities.valuationTime)?.extrinsicPerYear ?? null : null,
555
- putCostOfSpot: put ? optionCostOfSpot(put, spot) : null,
581
+ putCostOfSpot: put ? optionCostOfSpot(put, greeksSpot) : null,
556
582
  isPositionStrike: !!parsed && strike === parsed.strike,
557
583
  };
558
- }), [callsByStrike, dividendYield, greeksSpot, parsed, putsByStrike, spot, strikes, volatilities]);
584
+ }), [callsByStrike, dividendYield, greeksSpot, parsed, putsByStrike, strikes, volatilities]);
559
585
  // The open interest's session: the chain's own, or for a chain that does not say, OPX's listing of the
560
586
  // same expiry, stated only when the counts are OPX's.
561
587
  const statedOpenInterest = useMemo(() => strikeChain ? statedOpenInterestAsOf(strikeChain) : undefined, [strikeChain]);
@@ -566,7 +592,7 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
566
592
  const openInterestAsOf = useMemo(() => statedOpenInterest
567
593
  ?? (strikeChain && listedOpenInterest.data ? chainOpenInterestAsOf(strikeChain, listedOpenInterest.data) : null),
568
594
  [statedOpenInterest, strikeChain, listedOpenInterest.data]);
569
- // A report of the pane (`gloomberb fn OMON`) names them too.
595
+ // A report of the pane (`gloom fn OMON`) names them too.
570
596
  useRemoteUiNode(modelSpot ? {
571
597
  role: "report-notice",
572
598
  label: "Greeks spot",
@@ -584,10 +610,12 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
584
610
  } : null);
585
611
  // What IV and the Greeks are valued at, and the open interest's date. In a
586
612
  // crowded footer it shortens, then gives way to the contract under the cursor.
587
- const basisText = [modelSpot ? `spot ${formatModelSpotPrice(modelSpot.price)} ${modelSpotLabel(modelSpot)}` : null,
613
+ // A stamped spot (a close, an extended print) is already the Spot figure's.
614
+ const footerSpot = modelSpot && !modelSpotStamp(modelSpot) ? modelSpot : null;
615
+ const basisText = [footerSpot ? `spot ${formatModelSpotPrice(footerSpot.price)} ${modelSpotLabel(footerSpot)}` : null,
588
616
  strikeChain && !listedOpenInterest.loading ? openInterestAsOfLabel(openInterestAsOf) : null].filter(Boolean).join(" · ");
589
- const shortBasisText = [modelSpot ? `${formatModelSpotPrice(modelSpot.price)} ${modelSpot.basis === "close" ? "close" : modelSpot.session ?? "last"} `
590
- + `${new Date(modelSpot.observedAt).toISOString().slice(11, 16)} UTC` : null,
617
+ const shortBasisText = [footerSpot ? `${formatModelSpotPrice(footerSpot.price)} last `
618
+ + `${new Date(footerSpot.observedAt).toISOString().slice(11, 16)} UTC` : null,
591
619
  strikeChain && !listedOpenInterest.loading ? openInterestAsOf?.date ? `OI ${openInterestAsOf.date.slice(5)}` : "OI undated" : null]
592
620
  .filter(Boolean).join(" · ");
593
621
  usePaneFooter("options-basis", () => ({ info: basisText ? [{ id: "greeks-basis",
@@ -597,9 +625,9 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
597
625
  // busy stream reads as a steady strip rather than flicker.
598
626
  // A new expiry, a refreshed snapshot or the underlying price arriving or
599
627
  // going stale shows at once; only the stream itself is paced.
600
- const summaryResetKey = useMemo(() => ({}), [strikeSelectionKey, strikeChain, spot == null]);
628
+ const summaryResetKey = useMemo(() => ({}), [strikeSelectionKey, strikeChain, greeksSpot == null]);
601
629
  const summaryInput = useThrottledValue(
602
- useMemo(() => ({ chain: liveChain, spot, volatilities }), [liveChain, spot, volatilities]),
630
+ useMemo(() => ({ chain: liveChain, spot: greeksSpot, volatilities }), [liveChain, greeksSpot, volatilities]),
603
631
  OPTIONS_SUMMARY_THROTTLE_MS,
604
632
  summaryResetKey,
605
633
  );
@@ -613,7 +641,7 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
613
641
  instrument: baseRequest?.instrument ?? null, expiration: selectedExpiration,
614
642
  selectedEntry: strikeChain === expirationChain ? expirationChainEntry
615
643
  : strikeChain === initialChain ? initialChainEntry : null,
616
- catalogue: availableExpirations, spot, spotAsOf: underlying?.quote?.lastUpdated,
644
+ catalogue: availableExpirations, spot: greeksSpot, spotAsOf: modelSpot?.observedAt,
617
645
  liveChain: liveChain !== strikeChain ? liveChain : null,
618
646
  });
619
647
  const enrichment = expirationUnavailable ? null : enrichmentState.snapshot;
@@ -901,7 +929,7 @@ export function OptionsView({ width, height, focused, nestedInTabs = false, ivRa
901
929
  // The root insets the terminal body, so the band gets the width inside it.
902
930
  const statWidth = Math.max(1, width - (nativePaneChrome ? 0 : 2));
903
931
  const figures = optionsSummaryItems({
904
- spot: spotItem(underlying, isOpt ? undefined : ticker.metadata.assetCategory),
932
+ spot: spotItem(underlying, isOpt ? undefined : ticker.metadata.assetCategory, modelSpot),
905
933
  summary, enrichment, currency: underlying?.quote?.currency || ticker.metadata.currency || "",
906
934
  ivRank: showIvRank ? { stats: ivRank } : null,
907
935
  });
@@ -9,18 +9,56 @@ import { createCalculatorSurfaceDependencies, loadCalculatorSurfaceVol, type Cal
9
9
  const number = (value: number) => Number.isFinite(value) ? value.toFixed(6) : "--";
10
10
  const metric = (label: string, value: number, suffix = ""): HeadlessPaneEntry => ({ label, value, formatted: `${number(value)}${suffix}` });
11
11
 
12
+ /** What was typed for each input, by option key: the CLI's strings, a pane's settings. */
13
+ type EnteredInputs = Readonly<Record<string, unknown>>;
14
+ const PLAIN_DECIMAL = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/;
15
+ /** A computed number without float noise or padding: 73.15, 30, 60. */
16
+ const plain = (value: number) => Number.isFinite(value) ? String(Number(value.toPrecision(12))) : "--";
17
+
18
+ /**
19
+ * An input echoed as it was entered: the typed text when it was a plain
20
+ * decimal of this value (73.15 stays 73.15, 73.150 stays 73.150), else the
21
+ * number without padding. Percent inputs (`scale` 100) compare the typed
22
+ * percent with the decimal the model reads.
23
+ */
24
+ function enteredText(entered: EnteredInputs, key: string, value: number, scale = 1): string {
25
+ const raw = entered[key];
26
+ const text = typeof raw === "string" ? raw.trim() : "";
27
+ if (PLAIN_DECIMAL.test(text) && Number(plain(Number(text) / scale)) === Number(plain(value))) return text.replace(/^\+/, "");
28
+ return plain(value * scale);
29
+ }
30
+
31
+ /** A price or day count, at the precision it was entered. */
32
+ const input = (entered: EnteredInputs, label: string, key: string, value: number): HeadlessPaneEntry => (
33
+ { label, value, formatted: enteredText(entered, key, value) }
34
+ );
35
+
36
+ /** A volatility or rate in percent, as the options ask for it: 60%, never 0.600000. */
37
+ const percentInput = (entered: EnteredInputs, label: string, key: string, value: number): HeadlessPaneEntry => {
38
+ const text = enteredText(entered, key, value, 100);
39
+ return { label, value: Number(text), unit: "%", formatted: `${text}%` };
40
+ };
41
+
42
+ /** A volatility read off the surface was not typed, so it reads to the hundredth of a point. */
43
+ const surfacePercent = (label: string, value: number): HeadlessPaneEntry => {
44
+ const percent = Number((value * 100).toFixed(2));
45
+ return { label, value: percent, unit: "%", formatted: `${percent}%` };
46
+ };
47
+
12
48
  function report(draft: OptionCalcDraft, valuation: OptionValuation | null,
13
49
  implied: { volatility: number | null; note: string | null }, surface: CalculatorSurfaceVol | null,
14
- errors: string[], effectiveTreeSteps: number | null = null): HeadlessBundleResult {
50
+ errors: string[], effectiveTreeSteps: number | null = null, entered: EnteredInputs = {}): HeadlessBundleResult {
15
51
  const model = draft.pricingModel ?? "european";
16
52
  return {
17
53
  sections: [
18
54
  { title: "Inputs", entries: [
19
55
  ...(draft.symbol ? [{ label: "Underlying", value: draft.symbol }] : []),
20
56
  { label: "Model", value: model }, { label: "Side", value: draft.side },
21
- metric("Spot", draft.spot), metric("Strike", draft.strike), metric("Days to expiry", draft.daysToExpiry),
22
- metric("Volatility", draft.volatility, " decimal"), metric("Annual rate", draft.rate, " decimal"),
23
- metric("Annual dividend yield", draft.dividendYield, " decimal"),
57
+ input(entered, "Spot", "spot", draft.spot), input(entered, "Strike", "strike", draft.strike),
58
+ input(entered, "Days to expiry", "days", draft.daysToExpiry),
59
+ surface?.volatility != null ? surfacePercent("Volatility", draft.volatility) : percentInput(entered, "Volatility", "volatility", draft.volatility),
60
+ percentInput(entered, "Annual rate", "rate", draft.rate),
61
+ percentInput(entered, "Annual dividend yield", "dividendYield", draft.dividendYield),
24
62
  ...(model === "american" ? [{ label: "Requested tree steps", value: draft.steps ?? 400 }] : []),
25
63
  ...(effectiveTreeSteps != null && effectiveTreeSteps !== (draft.steps ?? 400)
26
64
  ? [{ label: "Effective tree steps", value: effectiveTreeSteps }] : []),
@@ -68,7 +106,8 @@ export const optionsCalculatorHeadless: HeadlessPaneDefinition<"bundle"> = {
68
106
  { key: "marketPrice", aliases: ["market-price"], type: "string", description: "Observed premium per unit for implied volatility inversion" },
69
107
  ],
70
108
  async load(args, ctx) {
71
- const draft = draftFromCalculatorInputs({ ...ctx.settings, ...args.options });
109
+ const entered = { ...ctx.settings, ...args.options };
110
+ const draft = draftFromCalculatorInputs(entered);
72
111
  const dividends = draft.dividends ?? [];
73
112
  if (draft.pricingModel !== "american" && dividends.some((dividend) => dividend.amount > 0)) {
74
113
  throw new Error("Discrete cash dividends require the American CRR model.");
@@ -83,7 +122,7 @@ export const optionsCalculatorHeadless: HeadlessPaneDefinition<"bundle"> = {
83
122
  spot: draft.spot, strike: draft.strike, daysToExpiry: draft.daysToExpiry, signal: ctx.signal,
84
123
  }, createCalculatorSurfaceDependencies(ctx.marketData, ctx.apiClient));
85
124
  if (surface.volatility == null || surface.error) return report(draft, null,
86
- { volatility: null, note: "Surface volatility unavailable" }, surface, [surface.error ?? "Surface volatility unavailable"]);
125
+ { volatility: null, note: "Surface volatility unavailable" }, surface, [surface.error ?? "Surface volatility unavailable"], null, entered);
87
126
  valuedDraft = { ...draft, volatility: surface.volatility };
88
127
  }
89
128
  ctx.signal.throwIfAborted();
@@ -93,6 +132,6 @@ export const optionsCalculatorHeadless: HeadlessPaneDefinition<"bundle"> = {
93
132
  const implied = valuedDraft.marketPrice > 0 ? valuedDraft.pricingModel === "american"
94
133
  ? solveBinomialImpliedVolatility(valuedDraft, valuedDraft.marketPrice, tree)
95
134
  : solveImpliedVolatility(valuedDraft, valuedDraft.marketPrice) : { volatility: null, note: null };
96
- return report(valuedDraft, valuation, implied, surface, [], effectiveTreeSteps);
135
+ return report(valuedDraft, valuation, implied, surface, [], effectiveTreeSteps, entered);
97
136
  },
98
137
  };
@@ -1,3 +1,4 @@
1
+ import { unavailableText } from "../../../components/ui/status";
1
2
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
3
  import { delayedFooterSegment, FieldGrid, KeyValueRow, QueryBar, usePaneFooter, usePaneNoticeFooter, type GridField } from "../../../components";
3
4
  import { CompositeChart } from "../../../components/chart/composite/composite-chart";
@@ -194,7 +195,7 @@ export function OptionsCalculatorPane({ focused, width, height }: PaneProps) {
194
195
  const calculation = useMemo(() => {
195
196
  const unavailable = seedError ?? (american ? dividendInput.error : null)
196
197
  ?? (surfaceSource && !draft.symbol ? "Choose an underlying ticker for surface IV." : null)
197
- ?? (surfaceSource && !surfaceResource.loading && surface?.volatility == null ? surface?.error ?? surfaceResource.error ?? "Surface IV unavailable." : null);
198
+ ?? (surfaceSource && !surfaceResource.loading && surface?.volatility == null ? surface?.error ?? surfaceResource.error ?? unavailableText("Surface IV") : null);
198
199
  if (unavailable || surfaceSource && surface?.volatility == null) {
199
200
  return { valuation: null, implied: { volatility: null, note: null }, problem: unavailable };
200
201
  }
@@ -400,7 +401,7 @@ function ContractPremiumChart({
400
401
  width: number;
401
402
  focused: boolean;
402
403
  }) {
403
- const empty = unavailable ? "Premium history unavailable." : series.length < 1 ? "No premium history." : undefined;
404
+ const empty = unavailable ? unavailableText("Premium history") : series.length < 1 ? "No premium history." : undefined;
404
405
  return (
405
406
  <Box flexDirection="column" paddingX={1} height={PREMIUM_CHART_ROWS} flexShrink={0}>
406
407
  {empty && !loading ? (
@@ -2,6 +2,8 @@ import type { HeadlessPaneDefinition, HeadlessPaneEntry } from "../../../types/p
2
2
  import { expirationOptionSeconds, expiryIsoDate, OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER } from "../../../utils/option-expiry";
3
3
  import { formatUtcTime } from "../../../utils/utc-time";
4
4
  import { loadGamma, loadOpenInterest, positioningSymbol, type GammaPayload, type OpenInterestPayload } from "./client";
5
+ import { listingFateReport, loadListingFate } from "../../../tickers/listing-fate";
6
+ import { resolveHeadlessInstrument } from "../shared/headless-market-data";
5
7
  import {
6
8
  ALL_EXPIRIES,
7
9
  expiryLabel,
@@ -10,6 +12,7 @@ import {
10
12
  formatDistance,
11
13
  formatGamma,
12
14
  formatLevel,
15
+ formatPositioningSpot,
13
16
  formatPayout,
14
17
  formatRatio,
15
18
  formatStrike,
@@ -49,7 +52,7 @@ function summary(openInterest: OpenInterestPayload, dealer: GammaPayload | null)
49
52
  { key: "oiDate", label: "Open interest as of", value: openInterest.oiDate },
50
53
  ];
51
54
  const textEntries: HeadlessPaneEntry[] = [
52
- { label: "Spot", value: spot, formatted: spot == null ? "--" : spotAsOf ? `${formatLevel(spot)} at ${time(spotAsOf)}` : formatLevel(spot) },
55
+ { label: "Spot", value: spot, formatted: formatPositioningSpot(spot, spotAsOf) },
53
56
  ...(dealer ? [{ label: "Quotes as of", value: dealer.quotesAsOf, formatted: time(dealer.quotesAsOf) }] : []),
54
57
  { label: "Open interest as of", value: openInterest.oiDate, formatted: openInterest.oiDate ?? "--" },
55
58
  ];
@@ -118,7 +121,7 @@ export const optionsPositioningHeadless = (initialTab: PositioningTab): Headless
118
121
  // VIX has no dealer gamma, so its expiries have no column for it.
119
122
  const expiryGamma = !(allExpiries instanceof Error) && allExpiries.total ? netGammaByExpiry(allExpiries) : null;
120
123
  const gammaColumn = allExpiries instanceof Error || !!allExpiries.total;
121
- const errors = [
124
+ const loadErrors = [
122
125
  ...openInterest.warnings,
123
126
  ...(dealer instanceof Error ? [`Dealer gamma: ${dealer.message}`] : [
124
127
  ...dealer.warnings,
@@ -126,6 +129,11 @@ export const optionsPositioningHeadless = (initialTab: PositioningTab): Headless
126
129
  ]),
127
130
  ...(everyExpiry instanceof Error ? [`Net GEX by expiry: ${everyExpiry.message}`] : []),
128
131
  ];
132
+ // A symbol with no listed open interest says what became of it when something did (TWTR stopped
133
+ // trading, FB is a fund now) in place of the load's errors.
134
+ const fate = openInterest.expiries.length || expiry ? null
135
+ : listingFateReport(await loadListingFate(await resolveHeadlessInstrument(ctx, symbol), ctx.marketData), { served: false }, loadErrors);
136
+ const errors = fate?.errors ?? loadErrors;
129
137
  const changes = openInterest.previousOiDate != null;
130
138
  const gammaShown = dealer instanceof Error || !dealer.total ? null : dealer;
131
139
  const scope = dealer instanceof Error ? null : dealer.expiry ? expiryLabel(dealer.expiry) : "all expiries";
@@ -173,7 +181,7 @@ export const optionsPositioningHeadless = (initialTab: PositioningTab): Headless
173
181
  ],
174
182
  complete: !!openInterest.expiries.length && !(dealer instanceof Error) && errors.length === 0,
175
183
  unavailableSymbols: openInterest.expiries.length ? [] : [symbol],
176
- errors,
184
+ errors, ...(fate?.notes.length ? { notes: fate.notes } : {}),
177
185
  metadata: {
178
186
  underlying: openInterest.underlying,
179
187
  oiDate: openInterest.oiDate,
@@ -1,5 +1,6 @@
1
1
  import { formatCompact, formatCompactAmount } from "../../../utils/format";
2
2
  import { formatExpDate } from "../../../utils/options";
3
+ import { modelSpotLabel, modelSpotStamp, modelSpotStampVariants, observedModelSpot } from "../options/model-spot";
3
4
 
4
5
  export type PositioningTab = "strikes" | "expiries" | "gex";
5
6
  export const POSITIONING_TABS: { value: PositioningTab; label: string }[] = [
@@ -66,6 +67,29 @@ export function formatRatio(value: number | null | undefined): string {
66
67
  export function formatLevel(value: number | null | undefined): string {
67
68
  return value == null || !Number.isFinite(value) ? "--" : value.toFixed(2);
68
69
  }
70
+ /**
71
+ * The spot Gloom Cloud read the distances and dealer gamma at, stamped as
72
+ * every options pane stamps its spot (`modelSpotStamp`), as a stat cell
73
+ * carries it: `pre-market Wed 21 Oct 09:35 UTC`, its shorter forms, then
74
+ * none, so the band keeps the columns it has in regular hours. Nothing for
75
+ * the regular session's price.
76
+ */
77
+ export function positioningSpotDetail(spot: number | null | undefined, spotAsOf: string | null | undefined):
78
+ { detail?: string; detailVariants?: string[] } {
79
+ const at = spotAsOf ? Date.parse(spotAsOf) : Number.NaN;
80
+ if (spot == null || !Number.isFinite(at)) return {};
81
+ const observed = observedModelSpot(spot, at);
82
+ const stamp = modelSpotStamp(observed);
83
+ return stamp ? { detail: stamp, detailVariants: [...modelSpotStampVariants(observed), ""] } : {};
84
+ }
85
+
86
+ /** The spot as a report says it: `770.88 pre-market Wed 21 Oct 09:35 UTC`, `770.10 last Wed 21 Oct 14:05 UTC`. */
87
+ export function formatPositioningSpot(spot: number | null | undefined, spotAsOf: string | null | undefined): string {
88
+ const at = spotAsOf ? Date.parse(spotAsOf) : Number.NaN;
89
+ if (spot == null || !Number.isFinite(spot)) return "--";
90
+ return Number.isFinite(at) ? `${formatLevel(spot)} ${modelSpotLabel(observedModelSpot(spot, at))}` : formatLevel(spot);
91
+ }
92
+
69
93
  /** Where a level sits against spot: +0.6%. */
70
94
  export function formatDistance(level: number | null | undefined, spot: number | null | undefined): string {
71
95
  if (level == null || spot == null || !(spot > 0)) return "--";