gloomberb 0.18.3 → 0.18.5

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 (1018) 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 +32 -1
  6. package/src/account/auth-model.ts +7 -3
  7. package/src/account/checkout-handoff.tsx +225 -0
  8. package/src/account/device-signin-dialog.tsx +2 -2
  9. package/src/account/device-signin.ts +2 -2
  10. package/src/account/upgrade-dialog.tsx +1 -1
  11. package/src/api-client/askg.ts +2 -2
  12. package/src/api-client/auth.ts +11 -6
  13. package/src/api-client/catalysts.ts +2 -1
  14. package/src/api-client/central-bank-rates.ts +6 -0
  15. package/src/api-client/collections.ts +5 -1
  16. package/src/api-client/cot.ts +2 -0
  17. package/src/api-client/crypto-etf-flows.ts +37 -0
  18. package/src/api-client/crypto-markets.ts +60 -0
  19. package/src/api-client/data.ts +98 -5
  20. package/src/api-client/doe.ts +15 -0
  21. package/src/api-client/equity-screener.ts +28 -0
  22. package/src/api-client/exchange-announcements.ts +38 -0
  23. package/src/api-client/fund-facts.ts +39 -0
  24. package/src/api-client/futures-curve.ts +9 -1
  25. package/src/api-client/hiring.ts +301 -0
  26. package/src/api-client/index.ts +182 -16
  27. package/src/api-client/live-scan.ts +91 -0
  28. package/src/api-client/market-discovery.ts +14 -0
  29. package/src/api-client/members.ts +18 -0
  30. package/src/api-client/mna.ts +6 -0
  31. package/src/api-client/paths.ts +18 -1
  32. package/src/api-client/request.ts +224 -26
  33. package/src/api-client/research-activity.ts +3 -10
  34. package/src/api-client/short-side-publications.ts +37 -0
  35. package/src/api-client/socket.ts +64 -4
  36. package/src/api-client/swap-curve.ts +35 -0
  37. package/src/api-client/themes.ts +7 -1
  38. package/src/api-client/types.ts +96 -2
  39. package/src/app/keybindings/index.ts +3 -0
  40. package/src/app/keybindings/labels.ts +18 -1
  41. package/src/app/keybindings/resolve.ts +14 -0
  42. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  43. package/src/app/runtime/broker-import.ts +43 -26
  44. package/src/app/runtime/desktop-deeplink.ts +5 -5
  45. package/src/app/runtime/plugin-bindings.ts +2 -2
  46. package/src/app/runtime/startup.ts +13 -0
  47. package/src/app/star-prompt/status-line.tsx +2 -2
  48. package/src/architecture/core-builtin-allowlist.json +5 -2
  49. package/src/architecture/ui-literals-allowlist.json +3 -3
  50. package/src/architecture/ui-tokens-allowlist.json +1 -1
  51. package/src/brokers/broker-portfolio-sync.ts +37 -0
  52. package/src/brokers/directory.ts +11 -0
  53. package/src/brokers/logos.ts +3 -1
  54. package/src/brokers/signed-in/adapter.ts +304 -26
  55. package/src/brokers/signed-in/client.ts +14 -2
  56. package/src/brokers/signed-in/connect.ts +10 -2
  57. package/src/brokers/sync-broker-instance.ts +9 -1
  58. package/src/capabilities/chart-series.ts +22 -6
  59. package/src/cli/bank-section.ts +1 -1
  60. package/src/cli/base-converter.ts +23 -14
  61. package/src/cli/central-bank-events.ts +1 -1
  62. package/src/cli/command-options.ts +59 -4
  63. package/src/cli/commands/api.ts +9 -6
  64. package/src/cli/commands/broker.ts +2 -2
  65. package/src/cli/commands/command-utils.ts +2 -2
  66. package/src/cli/commands/crypto-hints.ts +7 -20
  67. package/src/cli/commands/fred-series.ts +9 -2
  68. package/src/cli/commands/keybindings.ts +25 -2
  69. package/src/cli/commands/market.ts +1177 -278
  70. package/src/cli/commands/news-hints.ts +2 -2
  71. package/src/cli/commands/news-search.ts +59 -6
  72. package/src/cli/commands/options-chain.ts +59 -3
  73. package/src/cli/commands/options-leaps.ts +41 -26
  74. package/src/cli/commands/overview.ts +222 -61
  75. package/src/cli/commands/plugins.ts +9 -9
  76. package/src/cli/commands/remote.ts +13 -10
  77. package/src/cli/commands/search.ts +82 -46
  78. package/src/cli/commands/system.ts +27 -19
  79. package/src/cli/commands/themes.ts +1 -1
  80. package/src/cli/commands/ticker.ts +194 -48
  81. package/src/cli/context.ts +3 -2
  82. package/src/cli/desktop-pane-shot-view.ts +2 -2
  83. package/src/cli/desktop-pane-shot.ts +1 -1
  84. package/src/cli/earnings-calendar.ts +4 -4
  85. package/src/cli/entry.ts +18 -1
  86. package/src/cli/errors.ts +21 -3
  87. package/src/cli/exit-codes.ts +1 -1
  88. package/src/cli/export-source.ts +38 -4
  89. package/src/cli/freshness.ts +2 -8
  90. package/src/cli/fx-forward.ts +130 -0
  91. package/src/cli/fx-pair.ts +10 -9
  92. package/src/cli/glossary.ts +113 -20
  93. package/src/cli/help.ts +19 -13
  94. package/src/cli/history-export.ts +126 -0
  95. package/src/cli/history-rows.ts +226 -50
  96. package/src/cli/index-roots.ts +5 -45
  97. package/src/cli/index.ts +24 -18
  98. package/src/cli/known-gaps.ts +123 -27
  99. package/src/cli/listing-arg.ts +316 -46
  100. package/src/cli/name-entries.ts +30 -18
  101. package/src/cli/native-smoke.ts +2 -0
  102. package/src/cli/not-a-ticker.ts +19 -9
  103. package/src/cli/opentui-libc.ts +5 -0
  104. package/src/cli/options.ts +12 -0
  105. package/src/cli/pane-functions/capabilities.ts +75 -20
  106. package/src/cli/pane-functions/catalog.ts +24 -23
  107. package/src/cli/pane-functions/discovery.ts +1 -1
  108. package/src/cli/pane-functions/dom.ts +10 -7
  109. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  110. package/src/cli/pane-functions/freshness.ts +193 -30
  111. package/src/cli/pane-functions/function-help.ts +76 -30
  112. package/src/cli/pane-functions/headless.ts +59 -12
  113. package/src/cli/pane-functions/index.ts +28 -19
  114. package/src/cli/pane-functions/market-session.ts +15 -5
  115. package/src/cli/pane-functions/options.ts +22 -2
  116. package/src/cli/pane-functions/report-notices.ts +12 -4
  117. package/src/cli/pane-functions/report.ts +10 -6
  118. package/src/cli/pane-functions/resolver.ts +64 -11
  119. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  120. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  121. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  122. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  123. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  124. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  125. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  126. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  127. package/src/cli/pane-functions/shot-options.ts +8 -3
  128. package/src/cli/peso-dollar-rates.ts +79 -0
  129. package/src/cli/quote-answer.ts +45 -4
  130. package/src/cli/report-tables.ts +75 -19
  131. package/src/cli/restore-plugins.ts +42 -15
  132. package/src/cli/result.ts +164 -23
  133. package/src/cli/series-search.ts +5 -5
  134. package/src/cli/statement-filings.ts +19 -0
  135. package/src/cli/suffixed-listing-rows.ts +49 -0
  136. package/src/cli/symbol-args.ts +50 -15
  137. package/src/cli/symbol-cells.ts +120 -0
  138. package/src/cli/symbol-list.ts +198 -68
  139. package/src/cli/symbol-rows.ts +131 -25
  140. package/src/cli/ticker-resolution.ts +108 -11
  141. package/src/cli/treasury-yields.ts +5 -5
  142. package/src/cli/types.ts +2 -0
  143. package/src/cli/uncovered-instrument.ts +3 -3
  144. package/src/cli/unknown-command.ts +6 -6
  145. package/src/components/chart/composite/chart-layout.ts +131 -0
  146. package/src/components/chart/composite/composite-chart.tsx +395 -20
  147. package/src/components/chart/composite/format.ts +27 -0
  148. package/src/components/chart/composite/interactions.ts +7 -2
  149. package/src/components/chart/composite/legend.tsx +75 -3
  150. package/src/components/chart/composite/levels.ts +7 -0
  151. package/src/components/chart/composite/panel-gestures.ts +41 -0
  152. package/src/components/chart/composite/panel-labels.ts +2 -1
  153. package/src/components/chart/composite/panel-series.ts +1 -0
  154. package/src/components/chart/composite/panel-surface.tsx +314 -13
  155. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  156. package/src/components/chart/composite/range-statistics.ts +62 -0
  157. package/src/components/chart/composite/rasterizer.ts +44 -19
  158. package/src/components/chart/composite/scene.ts +20 -4
  159. package/src/components/chart/composite/series-axis-tags.tsx +16 -9
  160. package/src/components/chart/composite/text-renderer.ts +48 -21
  161. package/src/components/chart/composite/toolbar.tsx +52 -5
  162. package/src/components/chart/composite/types.ts +17 -0
  163. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  164. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  165. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  166. package/src/components/chart/composite/value-scale.ts +149 -0
  167. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  168. package/src/components/chart/core/pointer.ts +2 -0
  169. package/src/components/chart-table/index.ts +2 -0
  170. package/src/components/chart-table/read.tsx +74 -0
  171. package/src/components/command-bar/commands/collection-list.ts +41 -19
  172. package/src/components/command-bar/commands/collection.ts +9 -3
  173. package/src/components/command-bar/commands/direct/index.ts +1 -1
  174. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  175. package/src/components/command-bar/pane-templates/items.ts +59 -6
  176. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  177. package/src/components/command-bar/panel/prompt-binding.ts +0 -8
  178. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  179. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  180. package/src/components/command-bar/routes/root/results.ts +18 -4
  181. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  182. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  183. package/src/components/command-bar/routes/root/selection.ts +6 -1
  184. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  185. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  186. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  187. package/src/components/command-bar/selection-runtime.ts +50 -10
  188. package/src/components/command-bar/surface/index.tsx +24 -2
  189. package/src/components/command-bar/view-model.ts +7 -0
  190. package/src/components/command-bar/workflow/alert.ts +1 -1
  191. package/src/components/command-bar/workflow/broker.ts +2 -2
  192. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  193. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  194. package/src/components/command-bar/workflow/fields.ts +8 -2
  195. package/src/components/command-bar/workflow/ops.ts +18 -4
  196. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  197. package/src/components/command-bar/workflow/submit.ts +3 -2
  198. package/src/components/command-bar/workflow/tickers.ts +5 -1
  199. package/src/components/company-logo.tsx +39 -0
  200. package/src/components/data-table/sections.ts +4 -2
  201. package/src/components/form-modal/confirm.tsx +2 -1
  202. package/src/components/form-modal/request.ts +5 -0
  203. package/src/components/form-modal/routes.ts +4 -1
  204. package/src/components/index.ts +12 -6
  205. package/src/components/layout/header.tsx +33 -46
  206. package/src/components/layout/market-summary.ts +9 -6
  207. package/src/components/layout/pane/capture-status.ts +1 -1
  208. package/src/components/layout/pane/footer/index.tsx +1 -0
  209. package/src/components/layout/pane/footer/model.ts +38 -5
  210. package/src/components/layout/shell/chrome.ts +19 -6
  211. package/src/components/layout/shell/index.tsx +2 -1
  212. package/src/components/layout/shell/pane/layers.tsx +19 -1
  213. package/src/components/layout/status-bar.tsx +2 -2
  214. package/src/components/market-board/index.tsx +11 -3
  215. package/src/components/onboarding/onboarding-frame.tsx +1 -1
  216. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  217. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  218. package/src/components/onboarding/portfolio-step/positions-panel.tsx +2 -2
  219. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  220. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  221. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  222. package/src/components/pane-settings-dialog/value.ts +8 -1
  223. package/src/components/pane-settings-dialog.tsx +44 -13
  224. package/src/components/sign-in-code-panel.tsx +27 -19
  225. package/src/components/ui/column-grid.tsx +48 -4
  226. package/src/components/ui/country-flag-art.tsx +180 -0
  227. package/src/components/ui/country-flag.tsx +118 -12
  228. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  229. package/src/components/ui/data-table/opentui/model.ts +109 -2
  230. package/src/components/ui/data-table/types.ts +1 -1
  231. package/src/components/ui/display.tsx +10 -2
  232. package/src/components/ui/index.ts +3 -1
  233. package/src/components/ui/logo-mark.tsx +11 -2
  234. package/src/components/ui/query-bar.tsx +1 -1
  235. package/src/components/ui/row-notes.ts +79 -0
  236. package/src/core/state/app/layout.ts +6 -4
  237. package/src/core/state/app/state.ts +9 -0
  238. package/src/core/state/app/types.ts +3 -0
  239. package/src/data/cached-query.ts +8 -1
  240. package/src/data/config/chart-settings.ts +3 -3
  241. package/src/data/config/home.ts +10 -2
  242. package/src/data/config/layout.ts +4 -1
  243. package/src/data/config/store/node.ts +4 -0
  244. package/src/data/config/store/normalize.ts +13 -3
  245. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  246. package/src/data/json-storage.ts +2 -0
  247. package/src/data/saved-copies.ts +123 -0
  248. package/src/docs/snapshot.json +422 -112
  249. package/src/i18n/es.ts +30 -13
  250. package/src/i18n/ja.ts +30 -13
  251. package/src/i18n/ko.ts +30 -13
  252. package/src/i18n/zh-cn.ts +30 -13
  253. package/src/i18n/zh-tw.ts +30 -13
  254. package/src/layout/desks.ts +1 -1
  255. package/src/layout/launch-layout.ts +1 -1
  256. package/src/layout/pane-manager/floating-actions.ts +5 -3
  257. package/src/layout/pane-manager/floating.ts +43 -1
  258. package/src/layout/pane-manager/index.ts +2 -0
  259. package/src/layout/selected-ticker.ts +74 -0
  260. package/src/market-data/coordinator/financials.ts +10 -2
  261. package/src/market-data/coordinator/index.ts +3 -1
  262. package/src/market-data/coordinator/quotes.ts +4 -2
  263. package/src/market-data/depositary-pair.ts +251 -0
  264. package/src/market-data/futures-board.ts +1 -1
  265. package/src/market-data/futures-contract.ts +124 -40
  266. package/src/market-data/fx-closes.ts +17 -2
  267. package/src/market-data/hooks.tsx +19 -11
  268. package/src/market-data/market/change-basis.ts +81 -11
  269. package/src/market-data/market/dated-previous-close.ts +203 -0
  270. package/src/market-data/market/freshness.ts +34 -5
  271. package/src/market-data/market/futures-week.ts +68 -0
  272. package/src/market-data/market/period-return.ts +163 -0
  273. package/src/market-data/market/status.ts +16 -4
  274. package/src/market-data/market/trading-sessions.ts +13 -0
  275. package/src/market-data/market/year-to-date.ts +8 -13
  276. package/src/market-data/options-alternatives.ts +60 -0
  277. package/src/market-data/performance.ts +20 -14
  278. package/src/market-data/perpetual-premium.ts +32 -0
  279. package/src/market-data/published-apac-sessions.ts +2 -1
  280. package/src/market-data/published-futures-sessions.ts +69 -0
  281. package/src/market-data/quotes/contributions.ts +25 -3
  282. package/src/market-data/quotes/freshness.ts +42 -0
  283. package/src/market-data/quotes/intraday-bar.ts +37 -0
  284. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  285. package/src/market-data/quotes/resolution.ts +7 -2
  286. package/src/market-data/selectors.ts +3 -0
  287. package/src/market-data/tax-equivalent.ts +1 -1
  288. package/src/market-data/ticker-price-returns.ts +3 -1
  289. package/src/news/aggregator.ts +5 -1
  290. package/src/news/news-model.ts +4 -0
  291. package/src/news/types.ts +11 -0
  292. package/src/notifications/app-notifier.ts +1 -1
  293. package/src/notifications/notification-log.ts +6 -4
  294. package/src/plugins/auto-update.ts +2 -2
  295. package/src/plugins/builtin/account-management/index.tsx +1 -0
  296. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  297. package/src/plugins/builtin/alerts/alert-engine.ts +34 -20
  298. package/src/plugins/builtin/alerts/calendar-events.ts +429 -0
  299. package/src/plugins/builtin/alerts/cli.ts +533 -85
  300. package/src/plugins/builtin/alerts/command.ts +12 -10
  301. package/src/plugins/builtin/alerts/constants.ts +1 -1
  302. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  303. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  304. package/src/plugins/builtin/alerts/events.ts +107 -5
  305. package/src/plugins/builtin/alerts/fired-log.ts +119 -0
  306. package/src/plugins/builtin/alerts/format.ts +10 -3
  307. package/src/plugins/builtin/alerts/headless.ts +107 -41
  308. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  309. package/src/plugins/builtin/alerts/history-rows.ts +92 -0
  310. package/src/plugins/builtin/alerts/history.ts +2 -0
  311. package/src/plugins/builtin/alerts/index.tsx +107 -30
  312. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  313. package/src/plugins/builtin/alerts/levels.ts +3 -3
  314. package/src/plugins/builtin/alerts/live.ts +3 -3
  315. package/src/plugins/builtin/alerts/metric-command.ts +61 -0
  316. package/src/plugins/builtin/alerts/metric-data.ts +70 -0
  317. package/src/plugins/builtin/alerts/metric-model.ts +175 -0
  318. package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
  319. package/src/plugins/builtin/alerts/pane.tsx +130 -49
  320. package/src/plugins/builtin/alerts/price.ts +35 -0
  321. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  322. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  323. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  324. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  325. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  326. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  327. package/src/plugins/builtin/alerts/storage.ts +38 -12
  328. package/src/plugins/builtin/alerts/targets.ts +12 -3
  329. package/src/plugins/builtin/alerts/types.ts +3 -0
  330. package/src/plugins/builtin/analytics/index.tsx +8 -2
  331. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  332. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  333. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  334. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  335. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  336. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  337. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  338. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  339. package/src/plugins/builtin/attention/pane.tsx +6 -2
  340. package/src/plugins/builtin/awards/headless.ts +7 -3
  341. package/src/plugins/builtin/awards/model.ts +18 -0
  342. package/src/plugins/builtin/awards/pane.tsx +6 -3
  343. package/src/plugins/builtin/backtest/headless.ts +13 -8
  344. package/src/plugins/builtin/backtest/pane.tsx +9 -4
  345. package/src/plugins/builtin/backtest/presets.ts +29 -3
  346. package/src/plugins/builtin/backtest/rules.ts +41 -5
  347. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  348. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  349. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  350. package/src/plugins/builtin/broker-manager/index.tsx +24 -14
  351. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  352. package/src/plugins/builtin/broker-manager/model.ts +18 -3
  353. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  354. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  355. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  356. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  357. package/src/plugins/builtin/broker-trading/controller.ts +66 -24
  358. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  359. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  360. package/src/plugins/builtin/broker-trading/index.tsx +19 -1
  361. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  362. package/src/plugins/builtin/broker-trading/order-feed.ts +83 -10
  363. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  364. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  365. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  366. package/src/plugins/builtin/broker-trading/pane.tsx +111 -24
  367. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  368. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  369. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  370. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  371. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  372. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  373. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  374. package/src/plugins/builtin/builtin-plugin-meta.ts +2 -2
  375. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  376. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  377. package/src/plugins/builtin/catalysts/model.ts +51 -5
  378. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  379. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  380. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  381. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  382. package/src/plugins/builtin/changelog/index.tsx +1 -0
  383. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +4 -1
  384. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +3 -2
  385. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  386. package/src/plugins/builtin/chart-composer/cli-options.ts +7 -10
  387. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -3
  388. package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -0
  389. package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
  390. package/src/plugins/builtin/chart-composer/editor.tsx +9 -4
  391. package/src/plugins/builtin/chart-composer/formula.ts +71 -18
  392. package/src/plugins/builtin/chart-composer/headless-schema.ts +42 -29
  393. package/src/plugins/builtin/chart-composer/headless.ts +266 -37
  394. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  395. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  396. package/src/plugins/builtin/chart-composer/pane.tsx +144 -30
  397. package/src/plugins/builtin/chart-composer/presets.ts +50 -15
  398. package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
  399. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  400. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  401. package/src/plugins/builtin/chart-composer/session-history.ts +31 -28
  402. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  403. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  404. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +44 -31
  405. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  406. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  407. package/src/plugins/builtin/chat/content/command-suggestions.ts +92 -0
  408. package/src/plugins/builtin/chat/content/composer.tsx +13 -6
  409. package/src/plugins/builtin/chat/content/footer.tsx +6 -3
  410. package/src/plugins/builtin/chat/content/index.tsx +51 -22
  411. package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
  412. package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
  413. package/src/plugins/builtin/chat/index.tsx +23 -0
  414. package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
  415. package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
  416. package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
  417. package/src/plugins/builtin/chat/pane-links/commands.ts +265 -0
  418. package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
  419. package/src/plugins/builtin/chat/pane-links/open.ts +9 -2
  420. package/src/plugins/builtin/chat/people.ts +1 -1
  421. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
  422. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  423. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  424. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  425. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  426. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  427. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  428. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  429. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  430. package/src/plugins/builtin/cloud/plugin.tsx +1 -1
  431. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  432. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  433. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  434. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  435. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  436. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  437. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  438. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  439. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  440. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  441. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  442. package/src/plugins/builtin/company-attention/client.ts +117 -1
  443. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  444. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  445. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  446. package/src/plugins/builtin/company-attention/model.ts +33 -7
  447. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  448. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  449. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  450. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  451. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  452. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  453. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  454. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  455. package/src/plugins/builtin/composite-plugins.ts +2 -1
  456. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  457. package/src/plugins/builtin/connections/index.ts +1 -0
  458. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  459. package/src/plugins/builtin/correlation/headless.ts +5 -3
  460. package/src/plugins/builtin/cot/headless.ts +28 -6
  461. package/src/plugins/builtin/cot/model.ts +12 -0
  462. package/src/plugins/builtin/cot/pane.tsx +3 -2
  463. package/src/plugins/builtin/cpi/headless.ts +5 -1
  464. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  465. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  466. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  467. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  468. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  469. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  470. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  471. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  472. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  473. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  474. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  475. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  476. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  477. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  478. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  479. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  480. package/src/plugins/builtin/debug/index.tsx +1 -0
  481. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  482. package/src/plugins/builtin/docs/index.tsx +1 -1
  483. package/src/plugins/builtin/docs/pane.tsx +2 -2
  484. package/src/plugins/builtin/docs/targets.ts +1 -1
  485. package/src/plugins/builtin/doe/client.ts +5 -1
  486. package/src/plugins/builtin/doe/headless.ts +12 -6
  487. package/src/plugins/builtin/doe/model.ts +43 -6
  488. package/src/plugins/builtin/doe/pane.tsx +18 -11
  489. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  490. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  491. package/src/plugins/builtin/earnings/board.tsx +253 -50
  492. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  493. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  494. package/src/plugins/builtin/earnings/client.ts +4 -3
  495. package/src/plugins/builtin/earnings/headless.ts +53 -15
  496. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  497. package/src/plugins/builtin/earnings/index.tsx +15 -22
  498. package/src/plugins/builtin/earnings/model.ts +17 -12
  499. package/src/plugins/builtin/earnings/scope.ts +89 -0
  500. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  501. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  502. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  503. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  504. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  505. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  506. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  507. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  508. package/src/plugins/builtin/econ/calendar-model.ts +144 -27
  509. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  510. package/src/plugins/builtin/econ/figures.ts +72 -0
  511. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  512. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  513. package/src/plugins/builtin/econ/index.tsx +144 -27
  514. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  515. package/src/plugins/builtin/econ/types.ts +34 -1
  516. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  517. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  518. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  519. package/src/plugins/builtin/econ-statistics/headless.ts +87 -28
  520. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  521. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  522. package/src/plugins/builtin/econ-statistics/stats.ts +104 -0
  523. package/src/plugins/builtin/econ-statistics/view.ts +19 -1
  524. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  525. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  526. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  527. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  528. package/src/plugins/builtin/equity-screener/pane.tsx +47 -12
  529. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  530. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  531. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  532. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  533. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  534. package/src/plugins/builtin/exposure/charts.tsx +2 -2
  535. package/src/plugins/builtin/exposure/headless.ts +51 -6
  536. package/src/plugins/builtin/exposure/index.tsx +28 -2
  537. package/src/plugins/builtin/exposure/model.ts +20 -1
  538. package/src/plugins/builtin/exposure/pane.tsx +10 -5
  539. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  540. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  541. package/src/plugins/builtin/futures/index.tsx +1 -0
  542. package/src/plugins/builtin/futures/model.ts +12 -10
  543. package/src/plugins/builtin/futures/returns.ts +8 -36
  544. package/src/plugins/builtin/futures/table.tsx +3 -3
  545. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  546. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  547. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  548. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  549. package/src/plugins/builtin/fx-matrix/client.ts +20 -8
  550. package/src/plugins/builtin/fx-matrix/headless.ts +37 -16
  551. package/src/plugins/builtin/fx-matrix/index.tsx +25 -13
  552. package/src/plugins/builtin/fx-matrix/live-legs.ts +34 -0
  553. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  554. package/src/plugins/builtin/gpu/headless.ts +9 -4
  555. package/src/plugins/builtin/help/index.tsx +13 -3
  556. package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
  557. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  558. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  559. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  560. package/src/plugins/builtin/holders/client.ts +13 -1
  561. package/src/plugins/builtin/holders/format.ts +28 -17
  562. package/src/plugins/builtin/holders/headless.ts +46 -7
  563. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  564. package/src/plugins/builtin/holders/pane.tsx +79 -15
  565. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  566. package/src/plugins/builtin/holders/table-model.ts +2 -1
  567. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  568. package/src/plugins/builtin/insider/headless.ts +1 -1
  569. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  570. package/src/plugins/builtin/insider/signals.tsx +1 -1
  571. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  572. package/src/plugins/builtin/iv-history/client.ts +20 -0
  573. package/src/plugins/builtin/iv-history/headless.ts +7 -4
  574. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  575. package/src/plugins/builtin/iv-history/model.ts +13 -4
  576. package/src/plugins/builtin/iv-history/series.ts +3 -1
  577. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  578. package/src/plugins/builtin/jobs/model.ts +4 -15
  579. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  580. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  581. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  582. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  583. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  584. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  585. package/src/plugins/builtin/macro-day/model.ts +29 -8
  586. package/src/plugins/builtin/macro-day/pane.tsx +51 -13
  587. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  588. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  589. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  590. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  591. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  592. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  593. package/src/plugins/builtin/market-movers/client.ts +33 -19
  594. package/src/plugins/builtin/market-movers/footer.ts +2 -2
  595. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  596. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  597. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  598. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  599. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  600. package/src/plugins/builtin/market-movers/table.ts +4 -1
  601. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  602. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  603. package/src/plugins/builtin/members/breadth-pane.tsx +81 -0
  604. package/src/plugins/builtin/members/client.ts +19 -4
  605. package/src/plugins/builtin/members/headless.ts +24 -10
  606. package/src/plugins/builtin/members/index.tsx +9 -9
  607. package/src/plugins/builtin/members/model.ts +23 -4
  608. package/src/plugins/builtin/members/pane.tsx +31 -14
  609. package/src/plugins/builtin/mna/client.ts +1 -0
  610. package/src/plugins/builtin/mna/detail.tsx +20 -32
  611. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  612. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  613. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  614. package/src/plugins/builtin/mna/headless.ts +6 -13
  615. package/src/plugins/builtin/mna/model.ts +93 -15
  616. package/src/plugins/builtin/mna/pane.tsx +5 -4
  617. package/src/plugins/builtin/news/headless.ts +12 -6
  618. package/src/plugins/builtin/news/index.tsx +10 -1
  619. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  620. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  621. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  622. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  623. package/src/plugins/builtin/notes/cli.ts +49 -14
  624. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  625. package/src/plugins/builtin/options/analytics.ts +26 -2
  626. package/src/plugins/builtin/options/carry.ts +2 -2
  627. package/src/plugins/builtin/options/index.tsx +1 -1
  628. package/src/plugins/builtin/options/model-spot.ts +5 -2
  629. package/src/plugins/builtin/options/strike-window.ts +2 -1
  630. package/src/plugins/builtin/options/table.ts +1 -7
  631. package/src/plugins/builtin/options/view.tsx +30 -13
  632. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  633. package/src/plugins/builtin/options-positioning/client.ts +19 -0
  634. package/src/plugins/builtin/options-positioning/headless.ts +54 -14
  635. package/src/plugins/builtin/options-positioning/index.tsx +3 -3
  636. package/src/plugins/builtin/options-positioning/model.ts +47 -8
  637. package/src/plugins/builtin/options-positioning/pane.tsx +68 -38
  638. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  639. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  640. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  641. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  642. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  643. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  644. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  645. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  646. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  647. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  648. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  649. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  650. package/src/plugins/builtin/perps/freshness.ts +14 -9
  651. package/src/plugins/builtin/perps/headless.ts +3 -1
  652. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  653. package/src/plugins/builtin/perps/live-rows.ts +168 -0
  654. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  655. package/src/plugins/builtin/perps/pane.tsx +49 -26
  656. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  657. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  658. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  659. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  660. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  661. package/src/plugins/builtin/portfolio-list/cli/render.ts +54 -22
  662. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  663. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  664. package/src/plugins/builtin/portfolio-list/headless.ts +7 -4
  665. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  666. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  667. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  668. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  669. package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
  670. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  671. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  672. package/src/plugins/builtin/power/client.ts +4 -1
  673. package/src/plugins/builtin/power/evidence.ts +22 -7
  674. package/src/plugins/builtin/power/gas.tsx +5 -1
  675. package/src/plugins/builtin/power/pane.tsx +8 -1
  676. package/src/plugins/builtin/power/prices.tsx +10 -3
  677. package/src/plugins/builtin/rate-path/pane.tsx +2 -2
  678. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  679. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  680. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  681. package/src/plugins/builtin/research/event-model.ts +3 -1
  682. package/src/plugins/builtin/research/event-sources.ts +12 -4
  683. package/src/plugins/builtin/research/index.tsx +2 -1
  684. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  685. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  686. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  687. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  688. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  689. package/src/plugins/builtin/research/relative-valuation-pane.tsx +80 -13
  690. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  691. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  692. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  693. package/src/plugins/builtin/scanner/feed.ts +2 -2
  694. package/src/plugins/builtin/scanner/index.ts +24 -1
  695. package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
  696. package/src/plugins/builtin/scanner/live-feed.ts +168 -0
  697. package/src/plugins/builtin/scanner/live-headless.ts +114 -0
  698. package/src/plugins/builtin/scanner/live-model.ts +351 -0
  699. package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
  700. package/src/plugins/builtin/scanner/live-track.ts +186 -0
  701. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  702. package/src/plugins/builtin/sec/forms.ts +13 -0
  703. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  704. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  705. package/src/plugins/builtin/sec/headless.ts +85 -8
  706. package/src/plugins/builtin/sec/index.tsx +58 -12
  707. package/src/plugins/builtin/sectors/client.ts +2 -1
  708. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  709. package/src/plugins/builtin/series-inventory.ts +3 -0
  710. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  711. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  712. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  713. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  714. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  715. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  716. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  717. package/src/plugins/builtin/shared/macro-releases.ts +65 -0
  718. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  719. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  720. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  721. package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
  722. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  723. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  724. package/src/plugins/builtin/shared/use-quote-board.ts +8 -2
  725. package/src/plugins/builtin/shared/volatility/pricing.ts +7 -1
  726. package/src/plugins/builtin/short-interest/client.ts +2 -0
  727. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  728. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  729. package/src/plugins/builtin/short-interest/model.ts +70 -19
  730. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  731. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  732. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  733. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  734. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  735. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  736. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  737. package/src/plugins/builtin/short-interest/types.ts +9 -0
  738. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  739. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  740. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  741. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  742. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  743. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  744. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  745. package/src/plugins/builtin/themes/headless.ts +11 -6
  746. package/src/plugins/builtin/themes/model.ts +15 -5
  747. package/src/plugins/builtin/themes/pane.tsx +27 -8
  748. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  749. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  750. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  751. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  752. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  753. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  754. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  755. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  756. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  757. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  758. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  759. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  760. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  761. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  762. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  763. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  764. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  765. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  766. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  767. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  768. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  769. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  770. package/src/plugins/builtin/ticker-detail/quote-footer.ts +14 -4
  771. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  772. package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
  773. package/src/plugins/builtin/vol-surface/client.ts +7 -4
  774. package/src/plugins/builtin/vol-surface/headless.ts +71 -13
  775. package/src/plugins/builtin/vol-surface/index.tsx +2 -2
  776. package/src/plugins/builtin/vol-surface/model.ts +26 -9
  777. package/src/plugins/builtin/vol-surface/pane.tsx +44 -7
  778. package/src/plugins/builtin/vol-surface/tables.ts +31 -3
  779. package/src/plugins/builtin/volatility/dvol.ts +46 -0
  780. package/src/plugins/builtin/volatility/model.ts +5 -10
  781. package/src/plugins/builtin/volatility/pane.tsx +2 -2
  782. package/src/plugins/builtin/volatility/series.ts +26 -0
  783. package/src/plugins/builtin/world-indices/footer.ts +1 -1
  784. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  785. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  786. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  787. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  788. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  789. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  790. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  791. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  792. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  793. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  794. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  795. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  796. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  797. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  798. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  799. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  800. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  801. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  802. package/src/plugins/bundle.ts +1 -1
  803. package/src/plugins/catalog-browser.ts +15 -9
  804. package/src/plugins/compat.ts +3 -3
  805. package/src/plugins/dependencies.ts +75 -14
  806. package/src/plugins/extracted-plugins.ts +132 -34
  807. package/src/plugins/host-link.ts +149 -34
  808. package/src/plugins/installer.ts +35 -10
  809. package/src/plugins/loader.ts +206 -38
  810. package/src/plugins/manager-node.ts +2 -2
  811. package/src/plugins/marketplace/deactivation.ts +22 -0
  812. package/src/plugins/marketplace/model.ts +2 -2
  813. package/src/plugins/marketplace/packs.ts +1 -1
  814. package/src/plugins/ownership.ts +1 -1
  815. package/src/plugins/peer-retry.ts +155 -0
  816. package/src/plugins/registry/contributions.ts +3 -1
  817. package/src/plugins/registry/index.ts +4 -3
  818. package/src/plugins/registry/plugin-state.ts +3 -0
  819. package/src/plugins/seed-notice.ts +20 -0
  820. package/src/plugins/shortcut-argument.ts +39 -0
  821. package/src/portfolio/allocation.ts +1 -1
  822. package/src/portfolio/collection-name.ts +31 -0
  823. package/src/portfolio/column-values.ts +15 -13
  824. package/src/portfolio/cost-fx.ts +296 -19
  825. package/src/portfolio/manual-lots.ts +75 -0
  826. package/src/portfolio/mutations.ts +60 -22
  827. package/src/portfolio/suffixed-listings.ts +209 -0
  828. package/src/portfolio/totals-currency.ts +24 -0
  829. package/src/public/__snapshots__/public-api.test.ts.snap +15 -0
  830. package/src/public/time-series.ts +11 -8
  831. package/src/remote/schema.ts +1 -1
  832. package/src/renderers/browser/app-services.ts +1 -7
  833. package/src/renderers/browser/config-host.ts +5 -55
  834. package/src/renderers/browser/main.tsx +30 -60
  835. package/src/renderers/dom/boot-frame-page.ts +187 -0
  836. package/src/renderers/dom/boot-frame.ts +237 -0
  837. package/src/renderers/dom/build-assets.ts +46 -8
  838. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  839. package/src/renderers/dom/host/ascii-text.ts +16 -2
  840. package/src/renderers/dom/host/box.tsx +43 -2
  841. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  842. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  843. package/src/renderers/dom/host/image-surface.tsx +49 -0
  844. package/src/renderers/dom/host/media-surface.tsx +24 -18
  845. package/src/renderers/dom/host/mouse.ts +30 -0
  846. package/src/renderers/dom/host/size-observer.ts +1 -1
  847. package/src/renderers/dom/host/style.ts +1 -1
  848. package/src/renderers/dom/styles.css +76 -0
  849. package/src/renderers/dom/test-utils.tsx +2 -1
  850. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  851. package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
  852. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  853. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  854. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  855. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  856. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  857. package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
  858. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
  859. package/src/renderers/electrobun/bun/desktop/update.ts +70 -3
  860. package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
  861. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  862. package/src/renderers/electrobun/bun/index.ts +36 -2
  863. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  864. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  865. package/src/renderers/electrobun/shared/app-name.ts +17 -0
  866. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  867. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  868. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  869. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  870. package/src/renderers/electrobun/view/config-host.ts +3 -0
  871. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
  872. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  873. package/src/renderers/electrobun/view/main.tsx +30 -4
  874. package/src/renderers/electrobun/view/news-source.ts +5 -5
  875. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  876. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  877. package/src/renderers/opentui/browser-open.ts +88 -0
  878. package/src/renderers/opentui/host.tsx +5 -14
  879. package/src/renderers/opentui/image/loader.ts +3 -2
  880. package/src/renderers/opentui/native-smoke.ts +10 -1
  881. package/src/renderers/opentui/pane-image/index.ts +2 -1
  882. package/src/renderers/opentui/render-lib.ts +253 -0
  883. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  884. package/src/renderers/opentui/start.tsx +1 -1
  885. package/src/renderers/opentui/toast-host.tsx +71 -43
  886. package/src/renderers/share/layout-view.tsx +2 -2
  887. package/src/renderers/share/main.tsx +4 -4
  888. package/src/renderers/share/view.tsx +1 -1
  889. package/src/series/resolve.ts +22 -6
  890. package/src/series/standalone.ts +30 -2
  891. package/src/series/types.ts +8 -1
  892. package/src/shares/api.ts +4 -1
  893. package/src/shares/pane.ts +1 -1
  894. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  895. package/src/sources/gloomberb-cloud/index.ts +32 -16
  896. package/src/sources/gloomberb-cloud/news.ts +39 -0
  897. package/src/sources/gloomberb-cloud/normalizers.ts +16 -1
  898. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  899. package/src/sources/listing-symbols.ts +37 -0
  900. package/src/sources/provider-errors.ts +16 -2
  901. package/src/sources/provider-router/batches.ts +10 -2
  902. package/src/sources/provider-router/financial-routes.ts +21 -3
  903. package/src/sources/provider-router/financials.ts +15 -2
  904. package/src/sources/provider-router/history.ts +58 -15
  905. package/src/sources/provider-router/index.ts +146 -10
  906. package/src/sources/provider-router/primary.ts +1 -1
  907. package/src/sources/provider-router/search.ts +13 -2
  908. package/src/state/app/bootstrap.ts +23 -0
  909. package/src/state/app/context/index.tsx +3 -0
  910. package/src/state/hooks/inline-tickers.ts +30 -5
  911. package/src/sync/auth-transition.ts +19 -9
  912. package/src/sync/baseline.ts +10 -4
  913. package/src/sync/controller.ts +67 -17
  914. package/src/sync/core-contributors.ts +46 -14
  915. package/src/sync/react.ts +4 -1
  916. package/src/sync/types.ts +3 -0
  917. package/src/team/collections-sync.ts +2 -1
  918. package/src/team/collections.ts +178 -17
  919. package/src/telemetry/crash-reports.ts +17 -4
  920. package/src/telemetry/usage-counts.ts +0 -18
  921. package/src/test-support/builtin-panes.ts +1 -1
  922. package/src/theme/colors.ts +11 -30
  923. package/src/theme/ui-tokens.ts +37 -1
  924. package/src/tickers/company-name-listing.ts +210 -33
  925. package/src/tickers/company-name.ts +59 -0
  926. package/src/tickers/index-roots.ts +47 -0
  927. package/src/tickers/instrument-label.ts +5 -1
  928. package/src/tickers/listing-venues.ts +23 -0
  929. package/src/tickers/metadata.ts +10 -0
  930. package/src/tickers/perpetual-listing.ts +5 -2
  931. package/src/tickers/search/bare-symbol.ts +36 -0
  932. package/src/tickers/search/home-listing.ts +75 -0
  933. package/src/tickers/search/index.ts +111 -33
  934. package/src/tickers/search/ranking.ts +64 -5
  935. package/src/tickers/search/types.ts +5 -0
  936. package/src/tickers/search/upsert.ts +29 -0
  937. package/src/tickers/terminal-codes.ts +416 -40
  938. package/src/time-series/bar-aggregation.ts +243 -0
  939. package/src/time-series/base-series.ts +315 -0
  940. package/src/time-series/chart-bounds.ts +349 -0
  941. package/src/time-series/chart-seed.ts +142 -0
  942. package/src/time-series/daily-valuation.ts +62 -0
  943. package/src/time-series/economic.ts +5 -0
  944. package/src/time-series/field-catalog.ts +1 -3
  945. package/src/time-series/forward-valuation.ts +32 -0
  946. package/src/time-series/fundamentals.ts +173 -10
  947. package/src/time-series/history-acquisition.ts +499 -0
  948. package/src/time-series/hooks.ts +1 -0
  949. package/src/time-series/leverage.ts +100 -0
  950. package/src/time-series/market-resolution.ts +4 -2
  951. package/src/time-series/market.ts +2 -1
  952. package/src/time-series/price-comparison.ts +175 -30
  953. package/src/time-series/price-units.ts +72 -2
  954. package/src/time-series/range.ts +9 -1
  955. package/src/time-series/resolution.ts +174 -16
  956. package/src/time-series/resolve-context.ts +161 -0
  957. package/src/time-series/resolve.ts +185 -1587
  958. package/src/time-series/series-name.ts +38 -0
  959. package/src/time-series/series-presentation.ts +242 -0
  960. package/src/time-series/spec.ts +13 -7
  961. package/src/time-series/studies.ts +377 -82
  962. package/src/time-series/tail-reconcile.ts +121 -0
  963. package/src/time-series/transforms.ts +1 -0
  964. package/src/time-series/types.ts +34 -2
  965. package/src/time-series/use-chart-resolution.ts +4 -5
  966. package/src/time-series/valuation-releases.ts +39 -0
  967. package/src/types/broker.ts +10 -0
  968. package/src/types/config.ts +14 -0
  969. package/src/types/data-provider.ts +23 -1
  970. package/src/types/desktop-window.ts +2 -0
  971. package/src/types/exchange-rate.ts +6 -0
  972. package/src/types/financials.ts +145 -8
  973. package/src/types/headless.ts +117 -9
  974. package/src/types/instrument.ts +6 -0
  975. package/src/types/plugin.ts +66 -9
  976. package/src/types/price-history.ts +2 -0
  977. package/src/types/ticker.ts +13 -0
  978. package/src/types/trading.ts +59 -1
  979. package/src/ui/ascii-font.ts +13 -1
  980. package/src/ui/host.tsx +6 -1
  981. package/src/updater/command-names.ts +180 -0
  982. package/src/updater/index.ts +10 -5
  983. package/src/utils/calendar-date.ts +32 -15
  984. package/src/utils/cash-runway.ts +241 -0
  985. package/src/utils/central-banks.ts +42 -0
  986. package/src/utils/cli-output.ts +259 -80
  987. package/src/utils/contract-month.ts +16 -0
  988. package/src/utils/crypto-pair.ts +61 -3
  989. package/src/utils/currency-units.ts +29 -0
  990. package/src/utils/datetime-format.ts +10 -0
  991. package/src/utils/debug-log.ts +1 -1
  992. package/src/utils/decimal-comma.ts +39 -6
  993. package/src/utils/exchange-announcements.ts +71 -0
  994. package/src/utils/exchange-rate-snapshot.ts +10 -0
  995. package/src/utils/financial-statements.ts +89 -5
  996. package/src/utils/format.ts +34 -16
  997. package/src/utils/fundamentals.ts +150 -34
  998. package/src/utils/fx-market-hours.ts +10 -1
  999. package/src/utils/latest-financial-period.ts +8 -0
  1000. package/src/utils/linux-libc.ts +54 -0
  1001. package/src/utils/market-capitalization.ts +111 -15
  1002. package/src/utils/max-drawdown.ts +64 -0
  1003. package/src/utils/network-failure.ts +86 -0
  1004. package/src/utils/option-expiry.ts +186 -7
  1005. package/src/utils/options.ts +10 -0
  1006. package/src/utils/plugin-proxy-hosts.json +1 -0
  1007. package/src/utils/price-earnings.ts +11 -5
  1008. package/src/utils/price-history.ts +23 -8
  1009. package/src/utils/price-window.ts +131 -0
  1010. package/src/utils/release-date.ts +47 -0
  1011. package/src/utils/sec.ts +3 -0
  1012. package/src/utils/throttled-fetch.ts +11 -4
  1013. package/src/utils/trailing-eps.ts +67 -0
  1014. package/src/utils/typed-text.ts +21 -0
  1015. package/src/utils/utc-time.ts +24 -1
  1016. package/src/version.ts +6 -0
  1017. package/src/cli/pane-functions/screenshot.ts +0 -2122
  1018. package/src/renderers/browser/first-screen.ts +0 -193
@@ -1,14 +1,40 @@
1
+ import type { PaneTemplateContext, ShortcutArgError } from "../../../types/plugin";
2
+ import { findNamedCollection, unknownCollectionArgError } from "../../../portfolio/collection-name";
1
3
  import type { PluginModule } from "../plugin-module";
2
4
  import { exposureHeadless } from "./headless";
3
5
  import { ExposurePane } from "./pane";
4
6
 
7
+ const SOURCE = /^(PORT|WATCH):(.+)$/i;
8
+
9
+ /**
10
+ * `EXPO PORT:Book` names a portfolio, and `WATCH:Watchlist` a watchlist, by
11
+ * name or id in any case, as `fn EXPO` reads them. The pane keeps its source
12
+ * by id (`PORT:book`), so the name is rewritten to the id it names.
13
+ */
14
+ function sourceInput(arg: string, context: PaneTemplateContext): string {
15
+ const source = SOURCE.exec(arg.trim());
16
+ if (!source) return arg;
17
+ const prefix = source[1]!.toUpperCase();
18
+ const match = findNamedCollection(prefix === "PORT" ? context.config.portfolios : context.config.watchlists, source[2]);
19
+ return match ? `${prefix}:${match.id}` : arg;
20
+ }
21
+
22
+ /** `EXPO PORT:Nope` or `EXPO WATCH:Nope` names a portfolio or watchlist nothing has; tickers and weights are read by the pane. */
23
+ function unknownSourceArg(arg: string, context: PaneTemplateContext): ShortcutArgError | null {
24
+ const source = SOURCE.exec(arg.trim());
25
+ if (!source) return null;
26
+ return source[1]!.toUpperCase() === "PORT"
27
+ ? unknownCollectionArgError(source[2]!, context.config.portfolios, "portfolio", (name) => `PORT:${name}`)
28
+ : unknownCollectionArgError(source[2]!, context.config.watchlists, "watchlist", (name) => `WATCH:${name}`);
29
+ }
30
+
5
31
  export const exposureModule: PluginModule = {
6
32
  panes: [{ id: "exposure", name: "Exposure", icon: "E", component: ExposurePane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 138, height: 31 }, tableExport: true, headless: exposureHeadless,
7
33
  personalData: "holdings",
8
34
  portableShare: { private: { params: true, settings: true, state: true } } }],
9
35
  paneTemplates: [{ id: "exposure-pane", paneId: "exposure", label: "Exposure", description: "Pro scenario exposures across holdings, geographic revenue and supply chains, with source evidence and portfolio concentrations.",
10
36
  keywords: ["exposure", "scenario", "stress", "portfolio", "supply", "country", "tariff", "pro"],
11
- shortcut: { prefix: "EXPO", argKind: "text", argOptional: true, argPlaceholder: "AAPL=60% NVDA=40%" }, headless: exposureHeadless,
12
- createInstance: (_context, options) => ({ params: { input: options?.arg ?? "" } }),
37
+ shortcut: { prefix: "EXPO", argKind: "text", argOptional: true, argPlaceholder: "AAPL=60% NVDA=40%", argError: unknownSourceArg }, headless: exposureHeadless,
38
+ createInstance: (context, options) => ({ params: { input: sourceInput(options?.arg ?? "", context) } }),
13
39
  }],
14
40
  };
@@ -1,12 +1,31 @@
1
1
  import type { ExposureBasis, ExposureComponent, ExposureExtensionObservation, ExposureHolding, ExposurePayload, ExposureRange, ExposureScenario } from "../../../api-client/exposure";
2
+ import { quarterLabel } from "../shared/earnings-report";
2
3
  import { humanLabel } from "../shared/research-cells";
3
4
 
4
5
  export const TABS = [{ value: "table", label: "Table" }, { value: "drivers", label: "Drivers" }, { value: "paths", label: "Paths" }, { value: "portfolio", label: "Portfolio" }];
5
6
  export const DEFAULT_SCENARIO: ExposureScenario = { id: "taiwan-disruption", label: "Taiwan disruption", shocks: [{ id: "taiwan", kind: "country", target: "TW", changePct: -100 }] };
7
+ /**
8
+ * The ids of Gloom Cloud's scenario library, which the catalog lists for
9
+ * `--scenario`. A report reads the library itself, so an id added there runs
10
+ * before it is listed here.
11
+ */
12
+ export const LIBRARY_SCENARIO_IDS = ["taiwan-disruption", "china-demand", "europe-demand", "china-semiconductor-ban", "china-tariff",
13
+ "oil-up", "rates-up", "usd-up", "tsmc-outage", "microsoft-capex"] as const;
6
14
  export const basisLabel = (basis: string | null) => basis?.replaceAll("_", " ") ?? "Unknown basis";
7
15
  const pct = (value: number) => `${value.toFixed(1)}%`;
8
16
  export const rangeText = (range: ExposureRange | null) => !range ? "Unknown" : range.low === range.high ? pct(range.low) : `${range.low.toFixed(1)} to ${range.high.toFixed(1)}%`;
9
17
  export const fraction = (value: number) => pct(value * 100);
18
+ /** "1 hop", "2 hops". */
19
+ export const hopsText = (count: number) => `${count} hop${count === 1 ? "" : "s"}`;
20
+ /**
21
+ * A reporting period as the tables word it. The server keys a quarter by its end date (`quarter:2026-07-31`), which
22
+ * reads as the month it ends in, Jul 2026, as the earnings events label a quarter; a date or a source's own words
23
+ * stay as they are.
24
+ */
25
+ export function periodText(period: string): string {
26
+ const quarter = /^quarter:(\d{4}-\d{2}(?:-\d{2})?)$/.exec(period);
27
+ return quarter ? quarterLabel(quarter[1]) : period;
28
+ }
10
29
 
11
30
  /** A weighted list is entirely explicit. Never silently fill missing weights or normalize shorts. */
12
31
  export function parseHoldings(text: string): ExposureHolding[] {
@@ -71,7 +90,7 @@ export function exposureCellText(row: ExposureRow, column: "label" | "basis" | "
71
90
  // What the number rests on, in words: disclosed by the company, estimated by a chain, or not visible.
72
91
  case "classification": return `${humanLabel(row.classification)}${row.incomplete && row.classification !== "unknown" ? " · partial" : ""}`;
73
92
  case "impact": return row.impact ? rangeText(row.impact) : "--";
74
- case "period": return row.period ?? "--";
93
+ case "period": return row.period ? periodText(row.period) : "--";
75
94
  case "weight": return fraction(row.weight ?? 0);
76
95
  }
77
96
  }
@@ -8,6 +8,7 @@ import { useAppSelector, useAsyncResource, useAutoRefresh, useMarketData, usePan
8
8
  import { useThemeColors } from "../../../theme/theme-context";
9
9
  import type { PaneProps } from "../../../types/plugin";
10
10
  import { Box, ScrollBox, Text, useRendererHost, useUiCapabilities } from "../../../ui";
11
+ import { withCountryFlag } from "../../../components/ui/country-flag";
11
12
  import { logFailure } from "../../../utils/log-failure";
12
13
  import { SignInWall } from "../cloud/auth-actions";
13
14
  import { CLOUD_PLAN_KEY, useCloudUpgradeAction } from "../shared/cloud-upgrade";
@@ -19,7 +20,7 @@ import { ExposurePathDiagram, ExposureRanges } from "./charts";
19
20
  import { fetchExposure, fetchScenarios, validateExposure } from "./client";
20
21
  import { ExposureEditor, type ExposureInputs } from "./editor";
21
22
  import { portfolioHoldings, watchlistHoldings } from "./holdings";
22
- import { basisLabel, DEFAULT_SCENARIO, exposureCellText, fraction, parseCustomScenario, parseHoldings, pathRows, portfolioRows, rangeText, tableRows, TABS, type ExposureRow } from "./model";
23
+ import { basisLabel, DEFAULT_SCENARIO, exposureCellText, fraction, hopsText, parseCustomScenario, parseHoldings, pathRows, periodText, portfolioRows, rangeText, tableRows, TABS, type ExposureRow } from "./model";
23
24
  import { useExposureEvidence } from "./evidence";
24
25
  import { driverRows, driverScope, driverUnits, driverValue } from "./drivers";
25
26
 
@@ -28,7 +29,7 @@ function EvidenceItem({ item }: { item: ExposureEvidence }) {
28
29
  const host = useRendererHost();
29
30
  return <Box flexDirection="column" paddingY={1}>
30
31
  <KeyValueRow labelWidth={20} label="Evidence" value={`${item.tier} · ${item.asOf ?? "undated"}`} detail={item.confidence === null ? undefined : `${Math.round(item.confidence * 100)}% confidence`} />
31
- <KeyValueRow labelWidth={20} label="Period / units" value={`${item.period ?? "unknown"} · ${item.units}${item.currency ? ` ${item.currency}` : ""}`} />
32
+ <KeyValueRow labelWidth={20} label="Period / units" value={`${item.period ? periodText(item.period) : "unknown"} · ${item.units}${item.currency ? ` ${item.currency}` : ""}`} />
32
33
  {item.revision ? <KeyValueRow labelWidth={20} label="Revision" value={item.revision} /> : null}
33
34
  {item.quote ? <Text fg={colors.textBright}>{item.quote}</Text> : <Text fg={colors.textDim}>{item.tier === "user" ? "User-supplied assumption" : "Structured observation; no verbatim quote"}</Text>}
34
35
  {item.url ? <ActionRow label="Open primary evidence" onPress={() => void host.openExternal(item.url!)} /> : null}
@@ -48,7 +49,7 @@ function ExposureDetail({ row, data, width }: { row: ExposureRow | null; data: E
48
49
  {Object.entries(row.driver.dimensions ?? {}).map(([key, value]) => <KeyValueRow key={key} labelWidth={20} label={humanLabel(key)} value={value} />)}
49
50
  {row.driver.evidence.map(item => <EvidenceItem key={item.id} item={item} />)}
50
51
  </> : row ? <>
51
- <KeyValueRow labelWidth={20} label="Basis / period" value={`${basisLabel(row.basis)} · ${row.period ?? "unknown"}`} />
52
+ <KeyValueRow labelWidth={20} label="Basis / period" value={`${basisLabel(row.basis)} · ${row.period ? periodText(row.period) : "unknown"}`} />
52
53
  <KeyValueRow labelWidth={20} label={row.concentration ? "Gross exposure" : "Exposure"} value={rangeText(row.exposure)} detail={`${row.classification}${row.incomplete ? " · incomplete bound" : ""}`} />
53
54
  <KeyValueRow labelWidth={20} label={row.concentration ? "Signed exposure" : "Operating stress"} value={rangeText(row.impact)} detail={row.concentration ? "NAV-weighted operating exposure; not a scenario change" : "Estimated change in the stated denominator"} />
54
55
  {row.components.map(component => <Box key={component.id} flexDirection="column" paddingY={1}>
@@ -212,7 +213,11 @@ export function ExposurePane({ width, height, focused }: PaneProps) {
212
213
  case "value": return { text: row.driver ? driverValue(row.driver) : "--", value: row.driver?.value ?? null, color: colors.textBright };
213
214
  case "units": return { text: row.driver ? driverUnits(row.driver) : "", color: colors.textDim };
214
215
  case "scope": return { text: row.driver ? driverScope(row.driver) : "", color: colors.textDim };
215
- case "label": return { text: exposureCellText(row, "label"), color: unknown ? colors.textDim : colors.text };
216
+ case "label": {
217
+ const cell = { text: exposureCellText(row, "label"), color: unknown ? colors.textDim : colors.text };
218
+ // Grouped by country, each target leads with its flag on the desktop and the web.
219
+ return concentration && view === "country" ? withCountryFlag(cell, row.label, desktop) : cell;
220
+ }
216
221
  case "basis": return row.basis ? { text: exposureCellText(row, "basis"), color: colors.textDim } : missingCell(colors);
217
222
  case "exposure": return row.exposure ? { text: exposureCellText(row, "exposure"), value: row.exposure.high, color: colors.textBright } : { text: exposureCellText(row, "exposure"), value: null, color: colors.textMuted };
218
223
  // Disclosed figures stand out; estimates read plainly, and the word says which is which.
@@ -244,7 +249,7 @@ export function ExposurePane({ width, height, focused }: PaneProps) {
244
249
  const query = <QueryBar width={width} filters={[
245
250
  { id: "scenario", label: "Scenario", value: scenarioId, options: [...(library.data ?? [DEFAULT_SCENARIO]).map(s => ({ value: s.id ?? (snapshot ? "captured" : "custom"), label: s.label })), { value: "custom", label: "Custom" }].filter((s, i, all) => all.findIndex(v => v.value === s.value) === i), onChange: (value: string) => { if (value === "custom") setEditing(true); else setScenarioId(value); } },
246
251
  ...(tab === "portfolio" ? [{ id: "group", label: "View", value: view, options: [{ value: "stress", label: "Stress" }, { value: "country", label: "Country" }, { value: "supplier", label: "Supplier" }, { value: "customer", label: "Customer" }], onChange: setView }] : []),
247
- ]} meta={tab === "drivers" ? "Company disclosures" : tab === "portfolio" ? "NAV-weighted operating exposure" : `${data?.depth ?? inputs.depth} hops`} />;
252
+ ]} meta={tab === "drivers" ? "Company disclosures" : tab === "portfolio" ? "NAV-weighted operating exposure" : hopsText(data?.depth ?? inputs.depth)} />;
248
253
  if (!data && isCloudSessionRequired(resource.error) && !editing) return <SignInWall placement="exposure-signin" action="analyze exposures" needsVerification={session.needsVerification} />;
249
254
  return <Box width={width} height={height} flexDirection="column">
250
255
  {strip}
@@ -63,7 +63,7 @@ export const fearGreedPlugin: GloomPlugin = {
63
63
  },
64
64
  ],
65
65
 
66
- // `gloomberb fear-greed`, as before the plugin moved out of the host. Runs
66
+ // `gloom fear-greed`, as before the plugin moved out of the host. Runs
67
67
  // without the pane cache attached when invoked from the CLI, so it always
68
68
  // fetches, which is what a CLI call wants anyway.
69
69
  cliCommands: [
@@ -22,7 +22,7 @@ function filingEventsLockNote(lock: PaneLock): Promise<string> {
22
22
  does: "it reads each 8-K and sums up what it said and who it names",
23
23
  shows: "them",
24
24
  free: [{
25
- text: (ticker, company) => `gloomberb fn SEC ${ticker} lists ${company}'s recent filings, 8-Ks among them, each with its filing date and its items by number and name.`,
25
+ text: (ticker, company) => `gloom fn SEC ${ticker} lists ${company}'s recent filings, 8-Ks among them, each with its filing date and its items by number and name.`,
26
26
  answers: (symbol, context) => filesForm(symbol, "8-K", context),
27
27
  }],
28
28
  });
@@ -274,6 +274,7 @@ export function FuturesPane({ focused, width, height }: PaneProps) {
274
274
  noQuotes,
275
275
  status.latestTs,
276
276
  status.loading,
277
+ status.savedAt,
277
278
  status.stale,
278
279
  status.unavailable,
279
280
  ]);
@@ -4,6 +4,8 @@ import { compareSortValues, type SortDirection } from "../../../utils/sort-value
4
4
  import type { BoardQuoteMap } from "../shared/use-quote-board";
5
5
  import { FUTURES_SECTOR_ORDER, type FuturesContract, type FuturesSector } from "../../../market-data/futures-board";
6
6
  import { futuresPriceUnit } from "../../../market-data/futures-contract";
7
+ import { contractMonthLabel } from "../../../utils/contract-month";
8
+ import { quoteDotMarketState } from "../../../market-data/market/status";
7
9
  import type { FuturesReturnHorizon } from "./returns";
8
10
  import type { FuturesTermsMap } from "./use-board-terms";
9
11
  import type { FrontReturnsMap } from "./use-front-returns";
@@ -41,20 +43,20 @@ export function futuresRowId(row: FuturesTableRow): string {
41
43
  return row.type === "header" ? `header-${row.sector}` : row.contract.symbol;
42
44
  }
43
45
 
44
- /** "Nov 26" or "Futures,Nov-2026"; a hyphen takes only a whole year, since "Futures,Nov-20" is 2026 cut short. */
46
+ /** "Nov 2026", "Nov 26" or "Futures,Nov-2026"; a hyphen takes only a whole year, since "Futures,Nov-20" is 2026 cut short. */
45
47
  const CONTRACT_MONTH = /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(?: (\d{4}|\d{2})|-(\d{4}))$/i;
46
48
 
47
49
  /**
48
50
  * The alias stays the row identity while its quoted contract rolls, so the
49
51
  * label is the catalog name plus the quoted contract's month ("30-Year T-Bond
50
- * Dec 26"). Quote names arrive as "Crude Oil Nov 26", "Corn Futures,Dec-2026"
51
- * or cut off mid-month ("Futures,Dec-"); a month without a year is dropped
52
- * rather than guessed.
52
+ * Dec 2026"). Quote names arrive as "Crude Oil Nov 2026", "Crude Oil Nov 26",
53
+ * "Corn Futures,Dec-2026" or cut off mid-month ("Futures,Dec-"); a month
54
+ * without a year is dropped rather than guessed.
53
55
  */
54
56
  export function futuresContractName(contract: FuturesContract, quote?: Quote | null): string {
55
57
  const month = quotedContractMonth(contract, quote);
56
58
  if (!month) return contract.name;
57
- return `${contract.name} ${MONTH_NAMES[month.month]} ${String(month.year).slice(-2)}`;
59
+ return `${contract.name} ${contractMonthLabel(month.year, month.month)}`;
58
60
  }
59
61
 
60
62
  const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
@@ -82,9 +84,9 @@ function dayMonth(date: string): string {
82
84
  * The row's headline: the contract its quote prices, as futuresContractName
83
85
  * words it: the root's front month until its roll date. Two notes follow,
84
86
  * each from the day's facts. Once the continuous symbol has rolled while the
85
- * nearer month still trades, that month's last trade: "WTI Crude Oil Dec 26,
87
+ * nearer month still trades, that month's last trade: "WTI Crude Oil Dec 2026,
86
88
  * rolled (Nov expires 20 Oct)". When the day's volume put another month first,
87
- * that month: "WTI Crude Oil Nov 26, Dec most active". The terms only add a
89
+ * that month: "WTI Crude Oil Nov 2026, Dec most active". The terms only add a
88
90
  * note when they name the month the quote prices, so a roll between the two
89
91
  * loads never mixes months, and place the month when the quote's name carries
90
92
  * none. A name column too narrow for a note drops it, the last one first.
@@ -104,7 +106,7 @@ export function futuresContractHeadline(
104
106
  const month = agree ? quoted ?? termsMonth : quoted;
105
107
  if (!month) return contract.name;
106
108
  const priced = `${month.year}-${String(month.month + 1).padStart(2, "0")}`;
107
- const plain = `${contract.name} ${MONTH_NAMES[month.month]} ${String(month.year).slice(-2)}`;
109
+ const plain = `${contract.name} ${contractMonthLabel(month.year, month.month)}`;
108
110
  if (!agree) return plain;
109
111
  const notes: Array<{ text: string; min: string }> = [];
110
112
  const nearest = terms?.nearest;
@@ -117,7 +119,7 @@ export function futuresContractHeadline(
117
119
  if (active && /^\d{4}-\d{2}$/.test(active.deliveryMonth) && active.deliveryMonth !== priced) {
118
120
  // Another year's month says which year it is.
119
121
  const name = MONTH_NAMES[Number(active.deliveryMonth.slice(5, 7)) - 1];
120
- const label = active.deliveryMonth.slice(0, 4) === String(month.year) ? name : `${name} ${active.deliveryMonth.slice(2, 4)}`;
122
+ const label = active.deliveryMonth.slice(0, 4) === String(month.year) ? name : `${name} ${active.deliveryMonth.slice(0, 4)}`;
121
123
  notes.push({ text: `, ${label} most active`, min: `, ${label} most active` });
122
124
  }
123
125
  // The month the quote prices leads, so a column that clips the tail still shows it; a note keeps its place
@@ -168,7 +170,7 @@ function getSortValue(
168
170
  case "unit":
169
171
  return futuresUnitLabel(contract, terms?.get(contract.symbol)?.terms);
170
172
  case "status":
171
- return quote?.marketState === "REGULAR" ? 0 : 1;
173
+ return quoteDotMarketState(quote) === "REGULAR" ? 0 : 1;
172
174
  case "code":
173
175
  return contract.code;
174
176
  case "name":
@@ -1,5 +1,5 @@
1
1
  import type { PricePoint, Quote } from "../../../types/financials";
2
- import { calendarMonthsBefore } from "../../../utils/calendar-date";
2
+ import { periodReturn } from "../../../market-data/market/period-return";
3
3
  import type { FuturesContract } from "../../../market-data/futures-board";
4
4
  import { quotedContractMonth } from "./model";
5
5
 
@@ -9,7 +9,6 @@ export type FuturesReturnValues = Readonly<Record<FuturesReturnHorizon, number |
9
9
  export const NO_FUTURES_RETURNS: FuturesReturnValues = { "1W": null, "1M": null, YTD: null };
10
10
 
11
11
  const MONTH_CODES = "FGHJKMNQUVXZ";
12
- const DAY_MS = 86_400_000;
13
12
 
14
13
  /** Gloom symbol of one listed contract: LEZ26.CME. */
15
14
  function listedContractSymbol(contract: FuturesContract, year: number, month: number): string {
@@ -51,10 +50,6 @@ function utcDay(value: Date | string | number): string | null {
51
50
  return Number.isFinite(date.getTime()) ? date.toISOString().slice(0, 10) : null;
52
51
  }
53
52
 
54
- function shiftDay(day: string, days: number): string {
55
- return new Date(Date.parse(`${day}T00:00:00Z`) + days * DAY_MS).toISOString().slice(0, 10);
56
- }
57
-
58
53
  /** Dated closes, one per day, oldest first. History that crossed a JSON bridge carries string dates. */
59
54
  function dailyCloses(history: readonly PricePoint[]): DailyClose[] {
60
55
  const byDay = new Map<string, number>();
@@ -86,25 +81,10 @@ export function pickFrontContract(
86
81
  return best?.symbol ?? null;
87
82
  }
88
83
 
89
- /**
90
- * A baseline further than this before its target date is a hole in the
91
- * contract's trading (or a contract listed after the target), not its close.
92
- */
93
- const MAX_BASELINE_GAP_DAYS = 10;
94
-
95
- function closeOnOrBefore(closes: readonly DailyClose[], target: string): number | null {
96
- const earliest = shiftDay(target, -MAX_BASELINE_GAP_DAYS);
97
- for (let index = closes.length - 1; index >= 0; index -= 1) {
98
- const bar = closes[index]!;
99
- if (bar.day > target) continue;
100
- return bar.day >= earliest && bar.close > 0 ? bar.close : null;
101
- }
102
- return null;
103
- }
104
-
105
84
  /**
106
85
  * One contract's returns: the latest price against that same contract's close
107
- * a week, a calendar month, and a year-end earlier. The continuous alias's own
86
+ * on or before the same date a week and a calendar month earlier, and its
87
+ * last close of the year before (periodReturn). The continuous alias's own
108
88
  * series jumps at every roll (LE=F fell 6.3% on a July roll day), so its
109
89
  * history is never the baseline. `price` is the live quote, dated `asOf`;
110
90
  * without one the contract's last close stands in.
@@ -116,17 +96,9 @@ export function frontContractReturns(
116
96
  ): FuturesReturnValues {
117
97
  const closes = dailyCloses(history);
118
98
  const live = price != null && Number.isFinite(price) && asOf != null && Number.isFinite(asOf);
119
- const latest = live ? price : closes.at(-1)?.close;
120
- const latestDay = live ? utcDay(asOf) : closes.at(-1)?.day;
121
- if (latest == null || !latestDay) return NO_FUTURES_RETURNS;
122
- const change = (target: string) => {
123
- const base = closeOnOrBefore(closes, target);
124
- return base == null ? null : (latest / base - 1) * 100;
125
- };
126
- const monthBack = calendarMonthsBefore(new Date(`${latestDay}T00:00:00Z`), 1).toISOString().slice(0, 10);
127
- return {
128
- "1W": change(shiftDay(latestDay, -7)),
129
- "1M": change(monthBack),
130
- YTD: change(`${Number(latestDay.slice(0, 4)) - 1}-12-31`),
131
- };
99
+ const liveDay = live ? utcDay(asOf) : null;
100
+ const latest = live && liveDay ? { day: liveDay, close: price } : closes.at(-1);
101
+ if (!latest) return NO_FUTURES_RETURNS;
102
+ const change = (period: FuturesReturnHorizon) => periodReturn(closes, period, latest)?.percent ?? null;
103
+ return { "1W": change("1W"), "1M": change("1M"), YTD: change("YTD") };
132
104
  }
@@ -1,5 +1,5 @@
1
1
  import type { DataTableCell, DataTableColumn } from "../../../components";
2
- import { colors, priceColor } from "../../../theme/colors";
2
+ import { colors, shownPriceColor } from "../../../theme/colors";
3
3
  import type { Quote } from "../../../types/financials";
4
4
  import { TextAttributes } from "../../../ui";
5
5
  import { formatCompact, formatNumber, formatPercentRaw } from "../../../utils/format";
@@ -43,7 +43,7 @@ const DEFAULT_FUTURES_COLUMN_IDS = FUTURES_COLUMN_DEFS.map((column) => column.id
43
43
  * which the change in percent still gives. The previous close (the last price
44
44
  * less the change) goes first, then each row's quote time (the status line
45
45
  * dates the newest), which leaves a 1280-pixel shot room for "WTI Crude Oil
46
- * Dec 26, rolled (Nov expires 20 Oct)".
46
+ * Dec 2026, rolled (Nov expires 20 Oct)".
47
47
  */
48
48
  const COLUMN_MIN_PANE_WIDTH: Partial<Record<FuturesColumnId, number>> = {
49
49
  change: 100,
@@ -253,7 +253,7 @@ export function renderFuturesCell(
253
253
  if (isBoardRowLoading(state) || returns?.loading) return { text: "…", color: colors.textDim };
254
254
  const value = returns?.values[FUTURES_RETURN_COLUMNS[column.id]!];
255
255
  if (value == null || !Number.isFinite(value)) return { text: "—", color: colors.textDim };
256
- return { text: formatPercentRaw(value), color: priceColor(value) };
256
+ return { text: formatPercentRaw(value), color: shownPriceColor(value, 2) };
257
257
  }
258
258
  case "prevClose":
259
259
  if (isBoardRowLoading(state)) return { text: "…", color: colors.textDim };
@@ -1,10 +1,12 @@
1
+ import { logFailure } from "../../../utils/log-failure";
1
2
  import { apiClient } from "../../../api-client";
2
3
  import type { FuturesCurvePayload } from "../../../api-client/futures-curve";
3
4
  import { createPluginCache } from "../../../data/plugin-cache";
4
5
  import { isFuturesContractSpec } from "../../../market-data/futures-contract";
5
6
  import { loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
6
- import type { DataProvider } from "../../../types/data-provider";
7
- import { archivedFuturesCurve, curveLookbackDate, curveSpot, normalizeCurveRoot, unsupportedCurveRootMessage, withTradedExpirations, type CurveSpot } from "./model";
7
+ import type { AssetDataProvider, DataProvider } from "../../../types/data-provider";
8
+ import type { TimeRange } from "../../../time-series/range";
9
+ import { archivedFuturesCurve, curveLookbackDate, curveSpot, normalizeCurveRoot, spotBarsFromHistory, unsupportedCurveRootMessage, withSettleChanges, withTradedExpirations, type CurveSpot, type SpotBar } from "./model";
8
10
 
9
11
  export const futuresCurveCache = createPluginCache<FuturesCurvePayload>({
10
12
  kind: "futures-curve", source: "gloom-cloud", schemaVersion: 1,
@@ -53,26 +55,31 @@ export function validateFuturesCurve(data: FuturesCurvePayload, root: string): F
53
55
  const slope = data.slope;
54
56
  if (![slope.value, slope.annualizedRollYield].every(finiteOrNull)
55
57
  || ![slope.percentile, slope.rollPercentile].every(rank) || !Number.isInteger(slope.samples) || slope.samples < 0
56
- || slope.asOf !== null && !timestamp(slope.asOf)) throw new Error("The server returned an invalid futures spread");
58
+ || slope.asOf !== null && !timestamp(slope.asOf)
59
+ || slope.basis != null && slope.basis !== "last" && slope.basis !== "settle"
60
+ || slope.thinSymbol != null && typeof slope.thinSymbol !== "string") throw new Error("The server returned an invalid futures spread");
57
61
  return data;
58
62
  }
59
63
 
64
+ /** A live curve as every reader takes it: expiring on last trading days, its changes against the settlement shown. */
65
+ const liveCurve = (data: FuturesCurvePayload) => withSettleChanges(withTradedExpirations(data));
66
+
60
67
  export async function fetchFuturesCurve(root: string, client: Pick<typeof apiClient, "getCloudFuturesCurve"> = apiClient): Promise<FuturesCurvePayload> {
61
68
  const normalized = normalizeCurveRoot(root);
62
69
  if (!normalized) throw new Error(unsupportedCurveRootMessage(root));
63
- try { return withTradedExpirations(validateFuturesCurve(await client.getCloudFuturesCurve(normalized), normalized)); }
70
+ try { return liveCurve(validateFuturesCurve(await client.getCloudFuturesCurve(normalized), normalized)); }
64
71
  catch (error) { throw unavailableOnServer(error, "Futures curves are not available yet."); }
65
72
  }
66
73
 
67
74
  export function getCachedFuturesCurve(root: string): FuturesCurvePayload | null {
68
75
  const cached = futuresCurveCache.get(root, { allowExpired: true });
69
76
  // The pane revalidates this copy on mount; only the source or a failed refresh makes it stale.
70
- return cached?.data ? withTradedExpirations(cached.data) : null;
77
+ return cached?.data ? liveCurve(cached.data) : null;
71
78
  }
72
79
 
73
80
  export async function loadFuturesCurve(root: string, force = false): Promise<FuturesCurvePayload> {
74
81
  const { payload, stale, refreshError } = await loadCloudResource(futuresCurveCache, root, () => fetchFuturesCurve(root), { force });
75
- return { ...withTradedExpirations(payload), stale: stale || payload.stale, gaps: [...payload.gaps, ...(refreshError ? [refreshError] : [])] };
82
+ return { ...liveCurve(payload), stale: stale || payload.stale, gaps: [...payload.gaps, ...(refreshError ? [refreshError] : [])] };
76
83
  }
77
84
 
78
85
  /** The archived curve on a past date with the curves a week and a month before it. */
@@ -83,8 +90,8 @@ export async function loadFuturesCurveAsOf(root: string, date: string,
83
90
  try {
84
91
  const [curve, week, month] = await Promise.all([
85
92
  client.getCloudFuturesCurveAsOf(normalized, date),
86
- client.getCloudFuturesCurveAsOf(normalized, curveLookbackDate(date, 7)).catch(() => null),
87
- client.getCloudFuturesCurveAsOf(normalized, curveLookbackDate(date, 30)).catch(() => null),
93
+ client.getCloudFuturesCurveAsOf(normalized, curveLookbackDate(date, 7)).catch(logFailure("futures-curve.client", "Load week comparison curve failed", null)),
94
+ client.getCloudFuturesCurveAsOf(normalized, curveLookbackDate(date, 30)).catch(logFailure("futures-curve.client", "Load month comparison curve failed", null)),
88
95
  ]);
89
96
  if (!curve || curve.root !== normalized || !Array.isArray(curve.contracts) || !Array.isArray(curve.gaps)
90
97
  || curve.contracts.some((row) => !row || typeof row.symbol !== "string" || !Number.isFinite(row.price)
@@ -101,5 +108,29 @@ export async function loadFuturesCurveAsOf(root: string, date: string,
101
108
  * A failed read is a missing spot, never a failed report: the curve stands without its basis.
102
109
  */
103
110
  export async function loadCurveSpot(symbol: string, provider: Pick<DataProvider, "getQuote">, now = Date.now()): Promise<CurveSpot> {
104
- return curveSpot(symbol, await provider.getQuote(symbol, "").catch(() => null), now);
111
+ return curveSpot(symbol, await provider.getQuote(symbol, "").catch(logFailure("futures-curve.client", "Load curve spot quote failed", null)), now);
112
+ }
113
+
114
+ /** The last day of one-minute bars: the reach of a curve's trades a basis is read for, the far months' older ones aside. */
115
+ const SPOT_BAR_RANGE: TimeRange = "1D";
116
+
117
+ /**
118
+ * The spot pair's one-minute bars over the last day, read through the same
119
+ * history path the charts use, which the basis pairs each trade with by
120
+ * minute. Bars of any other size pair nothing, and a failed read has none:
121
+ * the curve stands without its basis, each blank saying why.
122
+ */
123
+ export async function loadCurveSpotBars(symbol: string,
124
+ provider: Pick<AssetDataProvider, "getPriceHistoryForResolutionWithMetadata" | "getPriceHistoryForResolution">, force = false): Promise<SpotBar[]> {
125
+ const context = force ? { cacheMode: "refresh" as const } : undefined;
126
+ try {
127
+ if (provider.getPriceHistoryForResolutionWithMetadata) {
128
+ const history = await provider.getPriceHistoryForResolutionWithMetadata(symbol, "", SPOT_BAR_RANGE, "1m", context);
129
+ return history.resolution && history.resolution !== "1m" ? [] : spotBarsFromHistory(history.points);
130
+ }
131
+ return provider.getPriceHistoryForResolution
132
+ ? spotBarsFromHistory(await provider.getPriceHistoryForResolution(symbol, "", SPOT_BAR_RANGE, "1m", context)) : [];
133
+ } catch (error) {
134
+ return logFailure("futures-curve.client", "Load curve spot bars failed", [] as SpotBar[])(error);
135
+ }
105
136
  }
@@ -4,8 +4,8 @@ import type { HeadlessPaneColumn, HeadlessPaneDefinition, HeadlessPaneEntry, Hea
4
4
  import { formatPercentRaw } from "../../../utils/format";
5
5
  import { DATE_OPTION_EXAMPLES } from "../../../utils/calendar-date";
6
6
  import { newestReportTime, oldestReportTime } from "../../../utils/utc-time";
7
- import { fetchFuturesCurve, loadCurveSpot, loadFuturesCurveAsOf } from "./client";
8
- import { basisSpotSymbol, BASIS_CONVENTION, blankBasisNote, catalogueCurveUnit, curveAsOfDate, curveBasisPercent, curveBasisRows, curveChangeText, curveContractCode, curvePrice, curveRoundedPrice, curveSpotLabel, curveSpotSource, curveSpreadLabel, curveTimestamp, curveUnitLabel, normalizeCurveRoot, shortDatedBasisNote, thinContractCount, unsupportedCurveRootMessage, type ContractBasis } from "./model";
7
+ import { fetchFuturesCurve, loadCurveSpot, loadCurveSpotBars, loadFuturesCurveAsOf } from "./client";
8
+ import { basisSpotSymbol, BASIS_CONVENTION, blankBasisNote, catalogueCurveUnit, curveAsOfDate, curveBasisPercent, curveBasisRows, curveChangeText, curveContractCode, curvePrice, curveRoundedPrice, curveSpotSource, curveSpreadLabel, curveTimestamp, curveNoTradeSince, curveUnitLabel, noTradeChangeNote, normalizeCurveRoot, shortDatedBasisNote, thinSpreadNotice, unpairedContractCount, unsupportedCurveRootMessage, type ContractBasis } from "./model";
9
9
  import { COMMODITIES_VIEW_STATE } from "../commodities-energy/view-state";
10
10
 
11
11
  /** The root a report shows when none is given. */
@@ -22,6 +22,11 @@ const basisValue = (value: number | null) => value == null ? null : Number(value
22
22
  * every root. Prices and changes are at the root's tick precision. `price` is
23
23
  * the latest trade and `settlement` the exchange settlement for the curve's
24
24
  * settlement session (a past curve's settled rows have no separate trade).
25
+ * `change` is `price` less `settlement`; `noTradeSince` dates the settlement
26
+ * a contract has not traded since, whose change is therefore blank. A crypto
27
+ * root adds the basis: the spot in the minute of `price`'s trade and that
28
+ * minute (`spot`, `spotTime`), the fractional days from the trade to final
29
+ * settlement, and the premium and its yearly rate.
25
30
  */
26
31
  function contractRow(row: FuturesContract, data: FuturesCurvePayload, root: string, past: boolean, basis?: ContractBasis) {
27
32
  const price = (value: number | null | undefined) => curveRoundedPrice(value, root);
@@ -30,15 +35,21 @@ function contractRow(row: FuturesContract, data: FuturesCurvePayload, root: stri
30
35
  firstNotice: row.firstNotice ?? null, inDelivery: row.inDelivery ?? false,
31
36
  settlement: price(row.settlement), settlementDate: row.settlement != null ? data.settlementDate ?? null : null,
32
37
  price: past && row.settlement != null ? null : price(row.price), change: price(row.change),
38
+ noTradeSince: past ? null : curveNoTradeSince(row, data),
33
39
  asOf: row.asOf, stale: row.stale, volume: row.volume, openInterest: row.openInterest, percentile: rank(row.percentile),
34
40
  samples: row.samples, historyStart: row.historyStart, historyEnd: row.historyEnd,
35
41
  currency: row.currency, quoteUnit: curveUnitLabel(data) ?? row.quoteUnit, delayMinutes: row.delayMinutes,
36
- ...(basis ? { vsSpotPct: basisValue(basis.vsSpotPct), annualisedBasisPct: basisValue(basis.annualisedBasisPct) } : {}),
42
+ ...(basis ? { spot: price(basis.spot), spotTime: basis.spotTime, daysToExpiry: basisValue(basis.daysToExpiry),
43
+ vsSpotPct: basisValue(basis.vsSpotPct), annualisedBasisPct: basisValue(basis.annualisedBasisPct) } : {}),
37
44
  };
38
45
  }
39
46
 
40
- /** The text table: what a hedge reads, in one order for every root; JSON keeps every field. */
41
- function contractColumns(root: string, settlementDate: string | null, options: { basis: boolean; last: boolean; notice: boolean }): HeadlessPaneColumn[] {
47
+ /**
48
+ * The table: what a hedge reads, in one order for every root; JSON keeps every
49
+ * field. A crypto root's spot is the one each trade is read against; the
50
+ * export dates it, where the text leaves its minute to As Of UTC, the trade's.
51
+ */
52
+ function contractColumns(root: string, settlementDate: string | null, options: { basis: boolean; last: boolean; notice: boolean; text?: boolean }): HeadlessPaneColumn[] {
42
53
  const price = (value: unknown) => typeof value === "number" ? curvePrice(value, root) : "--";
43
54
  const date = (value: unknown) => typeof value === "string" ? value : "--";
44
55
  return [
@@ -51,7 +62,10 @@ function contractColumns(root: string, settlementDate: string | null, options: {
51
62
  // A Cboe price is the settlement itself, with no separate last trade.
52
63
  ...options.last ? [{ key: "price", header: "Last", align: "right" as const, format: price }] : [],
53
64
  { key: "change", header: "Change", align: "right", format: (value) => typeof value === "number" ? curveChangeText(value, root) : "--" },
54
- ...options.basis ? [{ key: "vsSpotPct", header: "Vs Spot", align: "right" as const, format: (value: unknown) => curveBasisPercent(typeof value === "number" ? value : null, 2) },
65
+ ...options.basis ? [{ key: "spot", header: "Spot", align: "right" as const, format: price },
66
+ ...options.text ? [] : [{ key: "spotTime", header: "Spot Time UTC", shrink: false, format: (value: unknown) => typeof value === "string" ? curveTimestamp(value) : "--" }],
67
+ { key: "vsSpotPct", header: "Vs Spot", align: "right" as const, format: (value: unknown) => curveBasisPercent(typeof value === "number" ? value : null, 2) },
68
+ { key: "daysToExpiry", header: "Days to Expiry", textHeader: "Days", align: "right" as const, format: (value: unknown) => typeof value === "number" ? value.toFixed(1) : "--" },
55
69
  { key: "annualisedBasisPct", header: "Ann Basis", align: "right" as const, format: (value: unknown) => curveBasisPercent(typeof value === "number" ? value : null, 1) }] : [],
56
70
  { key: "asOf", header: "As Of UTC", shrink: false, format: (value) => typeof value === "string" ? curveTimestamp(value) : "--" },
57
71
  { key: "openInterest", header: "Open Int", align: "right", format: (value) => typeof value === "number" ? value.toLocaleString("en-US") : "--" },
@@ -70,8 +84,9 @@ function fieldColumns(order: readonly string[], fields: object, formats: Record<
70
84
  .map((key) => ({ key, header: key, ...formats[key] ? { textFormat: formats[key] } : {} }));
71
85
  }
72
86
 
87
+ // `basis` says which prices the value subtracts: two last trades made together, or the settlements of the session in `asOf`.
73
88
  const FRONT_SPREAD_FIELDS = ["label", "frontSymbol", "nextSymbol", "value", "annualizedRollYield", "percentile", "rollPercentile",
74
- "samples", "historyStart", "historyEnd", "asOf", "state"];
89
+ "samples", "historyStart", "historyEnd", "asOf", "basis", "state", "thinSymbol"];
75
90
  const GHOST_FIELDS = ["symbol", "expiration", "price", "asOf"];
76
91
  /** The annualized roll yield reads as the percent it is (+32.36%); an export keeps the number. */
77
92
  const ROLL_YIELD_FORMAT = { annualizedRollYield: (value: unknown) => typeof value === "number" ? formatPercentRaw(value) : "--" };
@@ -93,7 +108,7 @@ function specEntries(data: FuturesCurvePayload): HeadlessPaneEntry[] {
93
108
  export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
94
109
  discovery: { aliases: ["CTM"], dataRequirements: ["Gloom Cloud futures curve endpoint"],
95
110
  limitations: ["Listed-contract catalogues can be incomplete.", "Ghosts and percentiles use the same listed contracts.", "Cboe VIX is daily settlement.",
96
- "Ann Basis is simple actual/365 on the latest trade against the spot quote, and noisy under 30 days to expiry."],
111
+ "Ann Basis is simple actual/365, each last trade against spot in the same minute, and noisy under 7 days to expiry."],
97
112
  intents: ["futures basis trade", "cash and carry", "basis against spot"] },
98
113
  shape: "bundle", argument: { kind: "free-text", optional: true, placeholder: "root", description: "FUT root such as CL, ES, ZN or VX, or a CME crypto root (BTC, ETH, SOL, XRP). Defaults to ES." },
99
114
  // Only the pane reads the tab; the report always carries both.
@@ -106,23 +121,30 @@ export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
106
121
  const input = args.argument || DEFAULT_ROOT;
107
122
  const root = normalizeCurveRoot(input);
108
123
  if (!root) throw new Error(unsupportedCurveRootMessage(input));
109
- const date = curveAsOfDate(args.options.date);
124
+ const date = curveAsOfDate(args.options.date, new Date(), "--date");
110
125
  // The archive keeps no spot history, so a past curve has no basis.
111
126
  const spotSymbol = date ? null : basisSpotSymbol(root);
112
127
  const now = Date.now();
113
- const [data, spot] = await Promise.all([
128
+ // The quote names the spot and its feed; the one-minute bars price each trade's own minute.
129
+ const [data, spot, bars] = await Promise.all([
114
130
  date ? loadFuturesCurveAsOf(root, date, ctx.apiClient) : fetchFuturesCurve(root, ctx.apiClient),
115
131
  spotSymbol ? loadCurveSpot(spotSymbol, ctx.marketData, now) : null,
132
+ spotSymbol ? loadCurveSpotBars(spotSymbol, ctx.marketData, ctx.refresh === true) : null,
116
133
  ]);
117
- const bases = spot ? curveBasisRows(data.contracts, spot) : null;
134
+ const bases = spot && bars ? curveBasisRows(data.contracts, bars) : null;
118
135
  const unit = curveUnitLabel(data);
119
136
  const terms = specEntries(data);
120
137
  const source = spot ? curveSpotSource(spot) : null;
121
138
  const notices = [...args.argument ? [] : [`Showing ${DEFAULT_ROOT}. Try fn CTM ${EXAMPLE_ROOT}.`],
122
- ...spot ? [spot.status === "ok" ? `Basis against ${curveSpotLabel(spot, root, now)}${source ? ` (${source})` : ""}; not the CME reference rate.` : `Basis blank: ${spot.reason}.`] : []];
139
+ ...spot ? [`Basis against ${spot.symbol} spot in each last trade's own minute${source ? ` (${source})` : ""}; not the CME reference rate.`] : []];
123
140
  // The footnotes under the table: the convention, why a cell is blank, and where a short-dated rate is not to be trusted.
124
- // Against a spot that is not usable every cell is blank for the spot's reason, which the notice above already gives.
125
- const notes = spot && bases ? [BASIS_CONVENTION, ...spot.status === "ok" ? [blankBasisNote(data.contracts, bases), shortDatedBasisNote(data.contracts, bases, spot)].filter((note): note is string => !!note) : []] : [];
141
+ const basisNotes = bases ? [BASIS_CONVENTION, blankBasisNote(data.contracts, bases), shortDatedBasisNote(data.contracts, bases)]
142
+ .filter((note): note is string => !!note) : [];
143
+ // A blank Change says why, as a blank basis does; a past curve has no session change to blank.
144
+ const changeNote = date ? null : noTradeChangeNote(data.contracts, data);
145
+ const thinSpread = thinSpreadNotice(data);
146
+ const notes = [...thinSpread ? [`${thinSpread}.`] : [], ...changeNote ? [changeNote] : [], ...basisNotes];
147
+ const columnOptions = { basis: !!bases, last: data.source !== "cboe", notice: data.contracts.some((row) => row.firstNotice) };
126
148
  // Dated by the contracts' own quotes; the same-contract history rows are a year of context, not observations.
127
149
  const quoted = data.contracts.map((row) => row.asOf);
128
150
  const freshness: HeadlessPaneFreshness = date
@@ -132,8 +154,8 @@ export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
132
154
  return {
133
155
  freshness,
134
156
  sections: [
135
- { title: "Contracts", columns: contractColumns(root, data.settlementDate ?? null,
136
- { basis: !!spot, last: data.source !== "cboe", notice: data.contracts.some((row) => row.firstNotice) }),
157
+ { title: "Contracts", columns: contractColumns(root, data.settlementDate ?? null, columnOptions),
158
+ ...bases ? { textColumns: contractColumns(root, data.settlementDate ?? null, { ...columnOptions, text: true }) } : {},
137
159
  rows: data.contracts.map((row) => contractRow(row, data, root, !!date, bases?.get(row.symbol))) },
138
160
  { title: "Front spread", columns: fieldColumns(FRONT_SPREAD_FIELDS, data.slope, ROLL_YIELD_FORMAT), rows: [{ label: curveSpreadLabel(data.slope), ...data.slope, value: curveRoundedPrice(data.slope.value, root),
139
161
  annualizedRollYield: data.slope.annualizedRollYield == null ? null : Number(data.slope.annualizedRollYield.toFixed(2)),
@@ -144,7 +166,7 @@ export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
144
166
  ],
145
167
  errors: data.gaps,
146
168
  ...(notes.length ? { notes } : {}),
147
- metadata: { ...data, quoteUnit: unit, ...(spot && bases ? { spot, basisBlankedThin: thinContractCount(bases.values()) } : {}), ...(args.argument ? {} : { defaultArgument: DEFAULT_ROOT }),
169
+ metadata: { ...data, quoteUnit: unit, ...(spot && bases ? { spot, basisBlankedUnpaired: unpairedContractCount(bases.values()) } : {}), ...(args.argument ? {} : { defaultArgument: DEFAULT_ROOT }),
148
170
  ...(notices.length ? { notices } : {}),
149
171
  complete: data.status === "available", percentileBasis: "Same-contract observations within one year; actual sample start/end retained" },
150
172
  };