gloomberb 0.18.3 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (886) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/src/account/checkout-handoff.tsx +225 -0
  6. package/src/account/device-signin-dialog.tsx +2 -2
  7. package/src/account/device-signin.ts +2 -2
  8. package/src/account/upgrade-dialog.tsx +1 -1
  9. package/src/api-client/askg.ts +2 -2
  10. package/src/api-client/auth.ts +2 -2
  11. package/src/api-client/central-bank-rates.ts +6 -0
  12. package/src/api-client/collections.ts +5 -1
  13. package/src/api-client/cot.ts +2 -0
  14. package/src/api-client/crypto-etf-flows.ts +37 -0
  15. package/src/api-client/crypto-markets.ts +60 -0
  16. package/src/api-client/data.ts +84 -5
  17. package/src/api-client/doe.ts +15 -0
  18. package/src/api-client/equity-screener.ts +28 -0
  19. package/src/api-client/exchange-announcements.ts +38 -0
  20. package/src/api-client/fund-facts.ts +39 -0
  21. package/src/api-client/futures-curve.ts +9 -1
  22. package/src/api-client/hiring.ts +301 -0
  23. package/src/api-client/index.ts +22 -5
  24. package/src/api-client/market-discovery.ts +14 -0
  25. package/src/api-client/members.ts +6 -0
  26. package/src/api-client/mna.ts +6 -0
  27. package/src/api-client/paths.ts +18 -1
  28. package/src/api-client/request.ts +21 -4
  29. package/src/api-client/short-side-publications.ts +37 -0
  30. package/src/api-client/socket.ts +64 -4
  31. package/src/api-client/swap-curve.ts +35 -0
  32. package/src/api-client/themes.ts +7 -1
  33. package/src/api-client/types.ts +90 -2
  34. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  35. package/src/app/runtime/desktop-deeplink.ts +5 -5
  36. package/src/app/runtime/plugin-bindings.ts +2 -2
  37. package/src/app/runtime/startup.ts +13 -0
  38. package/src/app/star-prompt/status-line.tsx +2 -2
  39. package/src/architecture/core-builtin-allowlist.json +5 -2
  40. package/src/architecture/ui-literals-allowlist.json +3 -3
  41. package/src/architecture/ui-tokens-allowlist.json +1 -1
  42. package/src/brokers/broker-portfolio-sync.ts +37 -0
  43. package/src/brokers/directory.ts +11 -0
  44. package/src/brokers/logos.ts +3 -1
  45. package/src/brokers/signed-in/adapter.ts +304 -26
  46. package/src/brokers/signed-in/client.ts +14 -2
  47. package/src/brokers/signed-in/connect.ts +10 -2
  48. package/src/brokers/sync-broker-instance.ts +9 -1
  49. package/src/capabilities/chart-series.ts +22 -6
  50. package/src/cli/bank-section.ts +1 -1
  51. package/src/cli/base-converter.ts +23 -14
  52. package/src/cli/central-bank-events.ts +1 -1
  53. package/src/cli/command-options.ts +59 -4
  54. package/src/cli/commands/api.ts +9 -6
  55. package/src/cli/commands/broker.ts +2 -2
  56. package/src/cli/commands/command-utils.ts +2 -2
  57. package/src/cli/commands/crypto-hints.ts +7 -20
  58. package/src/cli/commands/fred-series.ts +4 -2
  59. package/src/cli/commands/keybindings.ts +2 -2
  60. package/src/cli/commands/market.ts +1117 -264
  61. package/src/cli/commands/news-hints.ts +2 -2
  62. package/src/cli/commands/news-search.ts +59 -6
  63. package/src/cli/commands/options-leaps.ts +41 -26
  64. package/src/cli/commands/overview.ts +121 -48
  65. package/src/cli/commands/plugins.ts +9 -9
  66. package/src/cli/commands/remote.ts +13 -10
  67. package/src/cli/commands/search.ts +64 -44
  68. package/src/cli/commands/system.ts +27 -19
  69. package/src/cli/commands/themes.ts +1 -1
  70. package/src/cli/commands/ticker.ts +192 -47
  71. package/src/cli/context.ts +3 -2
  72. package/src/cli/desktop-pane-shot-view.ts +2 -2
  73. package/src/cli/desktop-pane-shot.ts +1 -1
  74. package/src/cli/earnings-calendar.ts +4 -4
  75. package/src/cli/entry.ts +18 -1
  76. package/src/cli/errors.ts +20 -2
  77. package/src/cli/exit-codes.ts +1 -1
  78. package/src/cli/export-source.ts +10 -4
  79. package/src/cli/freshness.ts +2 -8
  80. package/src/cli/fx-forward.ts +130 -0
  81. package/src/cli/fx-pair.ts +10 -9
  82. package/src/cli/glossary.ts +64 -20
  83. package/src/cli/help.ts +19 -13
  84. package/src/cli/history-export.ts +126 -0
  85. package/src/cli/history-rows.ts +196 -43
  86. package/src/cli/index-roots.ts +5 -45
  87. package/src/cli/index.ts +24 -18
  88. package/src/cli/known-gaps.ts +118 -25
  89. package/src/cli/listing-arg.ts +300 -41
  90. package/src/cli/name-entries.ts +30 -18
  91. package/src/cli/native-smoke.ts +2 -0
  92. package/src/cli/not-a-ticker.ts +19 -9
  93. package/src/cli/opentui-libc.ts +5 -0
  94. package/src/cli/options.ts +12 -0
  95. package/src/cli/pane-functions/capabilities.ts +75 -20
  96. package/src/cli/pane-functions/catalog.ts +24 -23
  97. package/src/cli/pane-functions/discovery.ts +1 -1
  98. package/src/cli/pane-functions/dom.ts +10 -7
  99. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  100. package/src/cli/pane-functions/freshness.ts +174 -23
  101. package/src/cli/pane-functions/function-help.ts +66 -27
  102. package/src/cli/pane-functions/headless.ts +24 -11
  103. package/src/cli/pane-functions/index.ts +18 -16
  104. package/src/cli/pane-functions/options.ts +22 -2
  105. package/src/cli/pane-functions/report-notices.ts +12 -4
  106. package/src/cli/pane-functions/report.ts +5 -5
  107. package/src/cli/pane-functions/resolver.ts +47 -10
  108. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  109. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  110. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  111. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  112. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  113. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  114. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  115. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  116. package/src/cli/pane-functions/shot-options.ts +8 -3
  117. package/src/cli/peso-dollar-rates.ts +79 -0
  118. package/src/cli/quote-answer.ts +38 -3
  119. package/src/cli/report-tables.ts +61 -16
  120. package/src/cli/restore-plugins.ts +29 -14
  121. package/src/cli/result.ts +111 -22
  122. package/src/cli/series-search.ts +5 -5
  123. package/src/cli/statement-filings.ts +19 -0
  124. package/src/cli/suffixed-listing-rows.ts +49 -0
  125. package/src/cli/symbol-args.ts +50 -15
  126. package/src/cli/symbol-cells.ts +120 -0
  127. package/src/cli/symbol-list.ts +198 -68
  128. package/src/cli/symbol-rows.ts +131 -25
  129. package/src/cli/ticker-resolution.ts +108 -11
  130. package/src/cli/treasury-yields.ts +5 -5
  131. package/src/cli/types.ts +2 -0
  132. package/src/cli/uncovered-instrument.ts +3 -3
  133. package/src/cli/unknown-command.ts +6 -6
  134. package/src/components/chart/composite/chart-layout.ts +131 -0
  135. package/src/components/chart/composite/composite-chart.tsx +373 -16
  136. package/src/components/chart/composite/interactions.ts +7 -2
  137. package/src/components/chart/composite/legend.tsx +75 -3
  138. package/src/components/chart/composite/levels.ts +5 -0
  139. package/src/components/chart/composite/panel-gestures.ts +41 -0
  140. package/src/components/chart/composite/panel-labels.ts +2 -1
  141. package/src/components/chart/composite/panel-surface.tsx +305 -11
  142. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  143. package/src/components/chart/composite/rasterizer.ts +44 -19
  144. package/src/components/chart/composite/scene.ts +16 -4
  145. package/src/components/chart/composite/text-renderer.ts +48 -21
  146. package/src/components/chart/composite/toolbar.tsx +52 -5
  147. package/src/components/chart/composite/types.ts +13 -0
  148. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  149. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  150. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  151. package/src/components/chart/composite/value-scale.ts +149 -0
  152. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  153. package/src/components/chart/core/pointer.ts +2 -0
  154. package/src/components/chart-table/index.ts +2 -0
  155. package/src/components/chart-table/read.tsx +74 -0
  156. package/src/components/command-bar/commands/collection-list.ts +41 -19
  157. package/src/components/command-bar/commands/collection.ts +9 -3
  158. package/src/components/command-bar/commands/direct/index.ts +1 -1
  159. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  160. package/src/components/command-bar/pane-templates/items.ts +59 -6
  161. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  162. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  163. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  164. package/src/components/command-bar/routes/root/results.ts +18 -4
  165. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  166. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  167. package/src/components/command-bar/routes/root/selection.ts +6 -1
  168. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  169. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  170. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  171. package/src/components/command-bar/selection-runtime.ts +50 -10
  172. package/src/components/command-bar/surface/index.tsx +24 -2
  173. package/src/components/command-bar/view-model.ts +7 -0
  174. package/src/components/command-bar/workflow/broker.ts +2 -2
  175. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  176. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  177. package/src/components/command-bar/workflow/fields.ts +8 -2
  178. package/src/components/command-bar/workflow/ops.ts +18 -4
  179. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  180. package/src/components/command-bar/workflow/submit.ts +3 -2
  181. package/src/components/command-bar/workflow/tickers.ts +5 -1
  182. package/src/components/company-logo.tsx +39 -0
  183. package/src/components/data-table/sections.ts +4 -2
  184. package/src/components/form-modal/confirm.tsx +2 -1
  185. package/src/components/form-modal/request.ts +5 -0
  186. package/src/components/form-modal/routes.ts +4 -1
  187. package/src/components/index.ts +12 -6
  188. package/src/components/layout/header.tsx +7 -6
  189. package/src/components/layout/market-summary.ts +9 -6
  190. package/src/components/layout/pane/capture-status.ts +1 -1
  191. package/src/components/layout/pane/footer/model.ts +11 -5
  192. package/src/components/layout/shell/chrome.ts +19 -6
  193. package/src/components/layout/shell/index.tsx +2 -1
  194. package/src/components/layout/shell/pane/layers.tsx +19 -1
  195. package/src/components/layout/status-bar.tsx +2 -2
  196. package/src/components/market-board/index.tsx +11 -3
  197. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  198. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  199. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  200. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  201. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  202. package/src/components/pane-settings-dialog/value.ts +8 -1
  203. package/src/components/pane-settings-dialog.tsx +44 -13
  204. package/src/components/sign-in-code-panel.tsx +27 -19
  205. package/src/components/ui/column-grid.tsx +48 -4
  206. package/src/components/ui/country-flag-art.tsx +180 -0
  207. package/src/components/ui/country-flag.tsx +118 -12
  208. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  209. package/src/components/ui/data-table/opentui/model.ts +109 -2
  210. package/src/components/ui/data-table/types.ts +1 -1
  211. package/src/components/ui/display.tsx +5 -1
  212. package/src/components/ui/index.ts +3 -1
  213. package/src/components/ui/logo-mark.tsx +11 -2
  214. package/src/components/ui/query-bar.tsx +1 -1
  215. package/src/components/ui/row-notes.ts +79 -0
  216. package/src/core/state/app/layout.ts +4 -4
  217. package/src/data/cached-query.ts +8 -1
  218. package/src/data/config/chart-settings.ts +3 -3
  219. package/src/data/config/home.ts +10 -2
  220. package/src/data/config/layout.ts +4 -1
  221. package/src/data/config/store/node.ts +4 -0
  222. package/src/data/config/store/normalize.ts +13 -3
  223. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  224. package/src/data/json-storage.ts +2 -0
  225. package/src/data/saved-copies.ts +84 -0
  226. package/src/docs/snapshot.json +65 -32
  227. package/src/i18n/es.ts +29 -12
  228. package/src/i18n/ja.ts +29 -12
  229. package/src/i18n/ko.ts +29 -12
  230. package/src/i18n/zh-cn.ts +29 -12
  231. package/src/i18n/zh-tw.ts +29 -12
  232. package/src/layout/desks.ts +1 -1
  233. package/src/layout/launch-layout.ts +1 -1
  234. package/src/layout/pane-manager/floating-actions.ts +5 -3
  235. package/src/layout/pane-manager/floating.ts +43 -1
  236. package/src/layout/pane-manager/index.ts +2 -0
  237. package/src/layout/selected-ticker.ts +74 -0
  238. package/src/market-data/depositary-pair.ts +251 -0
  239. package/src/market-data/futures-board.ts +1 -1
  240. package/src/market-data/futures-contract.ts +124 -40
  241. package/src/market-data/fx-closes.ts +17 -2
  242. package/src/market-data/hooks.tsx +19 -11
  243. package/src/market-data/market/change-basis.ts +49 -7
  244. package/src/market-data/market/freshness.ts +34 -5
  245. package/src/market-data/market/period-return.ts +163 -0
  246. package/src/market-data/market/trading-sessions.ts +13 -0
  247. package/src/market-data/market/year-to-date.ts +8 -13
  248. package/src/market-data/performance.ts +20 -14
  249. package/src/market-data/perpetual-premium.ts +32 -0
  250. package/src/market-data/published-apac-sessions.ts +2 -1
  251. package/src/market-data/published-futures-sessions.ts +69 -0
  252. package/src/market-data/quotes/contributions.ts +5 -1
  253. package/src/market-data/quotes/freshness.ts +42 -0
  254. package/src/market-data/quotes/intraday-bar.ts +37 -0
  255. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  256. package/src/market-data/quotes/resolution.ts +4 -2
  257. package/src/market-data/tax-equivalent.ts +1 -1
  258. package/src/market-data/ticker-price-returns.ts +3 -1
  259. package/src/news/aggregator.ts +5 -1
  260. package/src/news/news-model.ts +4 -0
  261. package/src/news/types.ts +11 -0
  262. package/src/notifications/app-notifier.ts +1 -1
  263. package/src/plugins/auto-update.ts +2 -2
  264. package/src/plugins/builtin/account-management/index.tsx +1 -0
  265. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  266. package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
  267. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  268. package/src/plugins/builtin/alerts/cli.ts +485 -76
  269. package/src/plugins/builtin/alerts/command.ts +5 -10
  270. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  271. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  272. package/src/plugins/builtin/alerts/events.ts +107 -5
  273. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  274. package/src/plugins/builtin/alerts/format.ts +2 -1
  275. package/src/plugins/builtin/alerts/headless.ts +100 -39
  276. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  277. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  278. package/src/plugins/builtin/alerts/index.tsx +45 -18
  279. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  280. package/src/plugins/builtin/alerts/levels.ts +3 -3
  281. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  282. package/src/plugins/builtin/alerts/price.ts +35 -0
  283. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  284. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  285. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  286. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  287. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  288. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  289. package/src/plugins/builtin/alerts/storage.ts +13 -10
  290. package/src/plugins/builtin/alerts/targets.ts +12 -3
  291. package/src/plugins/builtin/analytics/index.tsx +8 -2
  292. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  293. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  294. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  295. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  296. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  297. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  298. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  299. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  300. package/src/plugins/builtin/attention/pane.tsx +6 -2
  301. package/src/plugins/builtin/awards/headless.ts +7 -3
  302. package/src/plugins/builtin/awards/model.ts +18 -0
  303. package/src/plugins/builtin/awards/pane.tsx +6 -3
  304. package/src/plugins/builtin/backtest/headless.ts +3 -3
  305. package/src/plugins/builtin/backtest/rules.ts +41 -5
  306. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  307. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  308. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  309. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  310. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  311. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  312. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  313. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  314. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  315. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  316. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  317. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  318. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  319. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  320. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  321. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  322. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  323. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  324. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  325. package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
  326. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  327. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  328. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  329. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  330. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  331. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  332. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  333. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  334. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  335. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  336. package/src/plugins/builtin/catalysts/model.ts +49 -4
  337. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  338. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  339. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  340. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  341. package/src/plugins/builtin/changelog/index.tsx +1 -0
  342. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  343. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  344. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  345. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  346. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  347. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  348. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  349. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  350. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  351. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  352. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  353. package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
  354. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  355. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  356. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  357. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  358. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  359. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  360. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  361. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  362. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  363. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  364. package/src/plugins/builtin/chat/people.ts +1 -1
  365. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  366. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  367. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  368. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  369. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  370. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  371. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  372. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  373. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  374. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  375. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  376. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  377. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  378. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  379. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  380. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  381. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  382. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  383. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  384. package/src/plugins/builtin/company-attention/client.ts +117 -1
  385. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  386. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  387. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  388. package/src/plugins/builtin/company-attention/model.ts +33 -7
  389. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  390. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  391. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  392. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  393. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  394. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  395. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  396. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  397. package/src/plugins/builtin/composite-plugins.ts +2 -1
  398. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  399. package/src/plugins/builtin/connections/index.ts +1 -0
  400. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  401. package/src/plugins/builtin/correlation/headless.ts +5 -3
  402. package/src/plugins/builtin/cot/headless.ts +28 -6
  403. package/src/plugins/builtin/cot/model.ts +12 -0
  404. package/src/plugins/builtin/cot/pane.tsx +3 -2
  405. package/src/plugins/builtin/cpi/headless.ts +5 -1
  406. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  407. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  408. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  409. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  410. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  411. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  412. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  413. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  414. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  415. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  416. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  417. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  418. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  419. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  420. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  421. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  422. package/src/plugins/builtin/debug/index.tsx +1 -0
  423. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  424. package/src/plugins/builtin/docs/index.tsx +1 -1
  425. package/src/plugins/builtin/docs/pane.tsx +2 -2
  426. package/src/plugins/builtin/docs/targets.ts +1 -1
  427. package/src/plugins/builtin/doe/client.ts +5 -1
  428. package/src/plugins/builtin/doe/headless.ts +12 -6
  429. package/src/plugins/builtin/doe/model.ts +43 -6
  430. package/src/plugins/builtin/doe/pane.tsx +18 -11
  431. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  432. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  433. package/src/plugins/builtin/earnings/board.tsx +253 -50
  434. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  435. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  436. package/src/plugins/builtin/earnings/client.ts +4 -3
  437. package/src/plugins/builtin/earnings/headless.ts +53 -15
  438. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  439. package/src/plugins/builtin/earnings/index.tsx +15 -22
  440. package/src/plugins/builtin/earnings/model.ts +17 -12
  441. package/src/plugins/builtin/earnings/scope.ts +89 -0
  442. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  443. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  444. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  445. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  446. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  447. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  448. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  449. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  450. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  451. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  452. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  453. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  454. package/src/plugins/builtin/econ/index.tsx +112 -25
  455. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  456. package/src/plugins/builtin/econ/types.ts +32 -1
  457. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  458. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  459. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  460. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  461. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  462. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  463. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  464. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  465. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  466. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  467. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  468. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  469. package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
  470. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  471. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  472. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  473. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  474. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  475. package/src/plugins/builtin/exposure/headless.ts +51 -6
  476. package/src/plugins/builtin/exposure/index.tsx +28 -2
  477. package/src/plugins/builtin/exposure/model.ts +7 -0
  478. package/src/plugins/builtin/exposure/pane.tsx +6 -1
  479. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  480. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  481. package/src/plugins/builtin/futures/model.ts +10 -9
  482. package/src/plugins/builtin/futures/returns.ts +8 -36
  483. package/src/plugins/builtin/futures/table.tsx +1 -1
  484. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  485. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  486. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  487. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  488. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  489. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  490. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  491. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  492. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  493. package/src/plugins/builtin/gpu/headless.ts +9 -4
  494. package/src/plugins/builtin/help/index.tsx +13 -3
  495. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  496. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  497. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  498. package/src/plugins/builtin/holders/client.ts +13 -1
  499. package/src/plugins/builtin/holders/format.ts +28 -17
  500. package/src/plugins/builtin/holders/headless.ts +46 -7
  501. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  502. package/src/plugins/builtin/holders/pane.tsx +79 -15
  503. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  504. package/src/plugins/builtin/holders/table-model.ts +2 -1
  505. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  506. package/src/plugins/builtin/insider/headless.ts +1 -1
  507. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  508. package/src/plugins/builtin/insider/signals.tsx +1 -1
  509. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  510. package/src/plugins/builtin/iv-history/client.ts +20 -0
  511. package/src/plugins/builtin/iv-history/headless.ts +4 -4
  512. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  513. package/src/plugins/builtin/iv-history/model.ts +13 -4
  514. package/src/plugins/builtin/iv-history/series.ts +3 -1
  515. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  516. package/src/plugins/builtin/jobs/model.ts +4 -15
  517. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  518. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  519. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  520. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  521. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  522. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  523. package/src/plugins/builtin/macro-day/model.ts +29 -8
  524. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  525. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  526. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  527. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  528. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  529. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  530. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  531. package/src/plugins/builtin/market-movers/client.ts +33 -19
  532. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  533. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  534. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  535. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  536. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  537. package/src/plugins/builtin/market-movers/table.ts +4 -1
  538. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  539. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  540. package/src/plugins/builtin/members/headless.ts +6 -5
  541. package/src/plugins/builtin/members/pane.tsx +11 -4
  542. package/src/plugins/builtin/mna/client.ts +1 -0
  543. package/src/plugins/builtin/mna/detail.tsx +20 -32
  544. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  545. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  546. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  547. package/src/plugins/builtin/mna/headless.ts +6 -13
  548. package/src/plugins/builtin/mna/model.ts +93 -15
  549. package/src/plugins/builtin/mna/pane.tsx +5 -4
  550. package/src/plugins/builtin/news/headless.ts +12 -6
  551. package/src/plugins/builtin/news/index.tsx +10 -1
  552. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  553. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  554. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  555. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  556. package/src/plugins/builtin/notes/cli.ts +49 -14
  557. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  558. package/src/plugins/builtin/options/carry.ts +2 -2
  559. package/src/plugins/builtin/options/index.tsx +1 -1
  560. package/src/plugins/builtin/options/view.tsx +10 -10
  561. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  562. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  563. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  564. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  565. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  566. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  567. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  568. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  569. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  570. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  571. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  572. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  573. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  574. package/src/plugins/builtin/perps/freshness.ts +8 -5
  575. package/src/plugins/builtin/perps/headless.ts +3 -1
  576. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  577. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  578. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  579. package/src/plugins/builtin/perps/pane.tsx +36 -17
  580. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  581. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  582. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  583. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  584. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  585. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  586. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  587. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  588. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  589. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  590. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  591. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  592. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  593. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  594. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  595. package/src/plugins/builtin/power/client.ts +4 -1
  596. package/src/plugins/builtin/power/evidence.ts +22 -7
  597. package/src/plugins/builtin/power/gas.tsx +5 -1
  598. package/src/plugins/builtin/power/pane.tsx +8 -1
  599. package/src/plugins/builtin/power/prices.tsx +10 -3
  600. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  601. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  602. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  603. package/src/plugins/builtin/research/event-model.ts +3 -1
  604. package/src/plugins/builtin/research/event-sources.ts +12 -4
  605. package/src/plugins/builtin/research/index.tsx +2 -1
  606. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  607. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  608. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  609. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  610. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  611. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  612. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  613. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  614. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  615. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  616. package/src/plugins/builtin/sec/forms.ts +13 -0
  617. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  618. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  619. package/src/plugins/builtin/sec/headless.ts +85 -8
  620. package/src/plugins/builtin/sec/index.tsx +58 -12
  621. package/src/plugins/builtin/sectors/client.ts +2 -1
  622. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  623. package/src/plugins/builtin/series-inventory.ts +2 -0
  624. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  625. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  626. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  627. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  628. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  629. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  630. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  631. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  632. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  633. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  634. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  635. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  636. package/src/plugins/builtin/short-interest/client.ts +2 -0
  637. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  638. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  639. package/src/plugins/builtin/short-interest/model.ts +70 -19
  640. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  641. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  642. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  643. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  644. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  645. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  646. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  647. package/src/plugins/builtin/short-interest/types.ts +9 -0
  648. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  649. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  650. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  651. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  652. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  653. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  654. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  655. package/src/plugins/builtin/themes/headless.ts +8 -5
  656. package/src/plugins/builtin/themes/model.ts +14 -4
  657. package/src/plugins/builtin/themes/pane.tsx +24 -5
  658. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  659. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  660. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  661. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  662. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  663. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  664. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  665. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  666. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  667. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  668. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  669. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  670. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  671. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  672. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  673. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  674. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  675. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  676. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  677. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  678. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  679. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  680. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  681. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  682. package/src/plugins/builtin/vol-surface/client.ts +5 -4
  683. package/src/plugins/builtin/vol-surface/headless.ts +12 -3
  684. package/src/plugins/builtin/vol-surface/model.ts +4 -2
  685. package/src/plugins/builtin/volatility/model.ts +5 -10
  686. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  687. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  688. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  689. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  690. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  691. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  692. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  693. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  694. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  695. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  696. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  697. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  698. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  699. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  700. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  701. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  702. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  703. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  704. package/src/plugins/bundle.ts +1 -1
  705. package/src/plugins/catalog-browser.ts +2 -1
  706. package/src/plugins/compat.ts +3 -3
  707. package/src/plugins/dependencies.ts +75 -14
  708. package/src/plugins/extracted-plugins.ts +132 -34
  709. package/src/plugins/host-link.ts +149 -34
  710. package/src/plugins/installer.ts +35 -10
  711. package/src/plugins/loader.ts +206 -38
  712. package/src/plugins/manager-node.ts +2 -2
  713. package/src/plugins/marketplace/deactivation.ts +22 -0
  714. package/src/plugins/marketplace/model.ts +2 -2
  715. package/src/plugins/marketplace/packs.ts +1 -1
  716. package/src/plugins/ownership.ts +1 -1
  717. package/src/plugins/peer-retry.ts +155 -0
  718. package/src/plugins/registry/contributions.ts +3 -1
  719. package/src/plugins/registry/index.ts +4 -3
  720. package/src/plugins/registry/plugin-state.ts +3 -0
  721. package/src/plugins/seed-notice.ts +20 -0
  722. package/src/plugins/shortcut-argument.ts +39 -0
  723. package/src/portfolio/allocation.ts +1 -1
  724. package/src/portfolio/collection-name.ts +31 -0
  725. package/src/portfolio/column-values.ts +10 -8
  726. package/src/portfolio/cost-fx.ts +296 -19
  727. package/src/portfolio/manual-lots.ts +75 -0
  728. package/src/portfolio/mutations.ts +60 -22
  729. package/src/portfolio/suffixed-listings.ts +209 -0
  730. package/src/portfolio/totals-currency.ts +24 -0
  731. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  732. package/src/public/time-series.ts +11 -8
  733. package/src/remote/schema.ts +1 -1
  734. package/src/renderers/browser/config-host.ts +3 -0
  735. package/src/renderers/browser/main.tsx +23 -3
  736. package/src/renderers/dom/boot-frame-page.ts +187 -0
  737. package/src/renderers/dom/boot-frame.ts +237 -0
  738. package/src/renderers/dom/build-assets.ts +46 -8
  739. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  740. package/src/renderers/dom/host/ascii-text.ts +16 -2
  741. package/src/renderers/dom/host/box.tsx +43 -2
  742. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  743. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  744. package/src/renderers/dom/host/image-surface.tsx +49 -0
  745. package/src/renderers/dom/host/media-surface.tsx +24 -18
  746. package/src/renderers/dom/host/mouse.ts +30 -0
  747. package/src/renderers/dom/host/size-observer.ts +1 -1
  748. package/src/renderers/dom/host/style.ts +1 -1
  749. package/src/renderers/dom/styles.css +76 -0
  750. package/src/renderers/dom/test-utils.tsx +2 -1
  751. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  752. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  753. package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
  754. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  755. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  756. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  757. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  758. package/src/renderers/electrobun/bun/index.ts +11 -1
  759. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  760. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  761. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  762. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  763. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  764. package/src/renderers/electrobun/view/config-host.ts +3 -0
  765. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  766. package/src/renderers/electrobun/view/main.tsx +30 -4
  767. package/src/renderers/electrobun/view/news-source.ts +5 -5
  768. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  769. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  770. package/src/renderers/opentui/browser-open.ts +88 -0
  771. package/src/renderers/opentui/host.tsx +5 -14
  772. package/src/renderers/opentui/image/loader.ts +3 -2
  773. package/src/renderers/opentui/native-smoke.ts +10 -1
  774. package/src/renderers/opentui/pane-image/index.ts +2 -1
  775. package/src/renderers/opentui/render-lib.ts +253 -0
  776. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  777. package/src/renderers/opentui/start.tsx +1 -1
  778. package/src/renderers/share/layout-view.tsx +2 -2
  779. package/src/renderers/share/main.tsx +4 -4
  780. package/src/renderers/share/view.tsx +1 -1
  781. package/src/series/resolve.ts +22 -6
  782. package/src/series/standalone.ts +30 -2
  783. package/src/series/types.ts +8 -1
  784. package/src/shares/api.ts +4 -1
  785. package/src/shares/pane.ts +1 -1
  786. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  787. package/src/sources/gloomberb-cloud/index.ts +32 -16
  788. package/src/sources/gloomberb-cloud/news.ts +39 -0
  789. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  790. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  791. package/src/sources/listing-symbols.ts +37 -0
  792. package/src/sources/provider-errors.ts +16 -2
  793. package/src/sources/provider-router/financial-routes.ts +21 -3
  794. package/src/sources/provider-router/financials.ts +15 -2
  795. package/src/sources/provider-router/history.ts +30 -8
  796. package/src/sources/provider-router/primary.ts +1 -1
  797. package/src/state/app/bootstrap.ts +23 -0
  798. package/src/state/hooks/inline-tickers.ts +30 -5
  799. package/src/sync/controller.ts +1 -1
  800. package/src/sync/core-contributors.ts +46 -14
  801. package/src/team/collections-sync.ts +2 -1
  802. package/src/team/collections.ts +178 -17
  803. package/src/telemetry/crash-reports.ts +17 -4
  804. package/src/test-support/builtin-panes.ts +1 -1
  805. package/src/theme/colors.ts +3 -30
  806. package/src/theme/ui-tokens.ts +37 -1
  807. package/src/tickers/company-name-listing.ts +210 -33
  808. package/src/tickers/index-roots.ts +47 -0
  809. package/src/tickers/instrument-label.ts +5 -1
  810. package/src/tickers/metadata.ts +10 -0
  811. package/src/tickers/perpetual-listing.ts +5 -2
  812. package/src/tickers/search/home-listing.ts +75 -0
  813. package/src/tickers/search/index.ts +76 -27
  814. package/src/tickers/search/ranking.ts +54 -4
  815. package/src/tickers/search/upsert.ts +29 -0
  816. package/src/tickers/terminal-codes.ts +416 -40
  817. package/src/time-series/bar-aggregation.ts +243 -0
  818. package/src/time-series/base-series.ts +307 -0
  819. package/src/time-series/chart-bounds.ts +349 -0
  820. package/src/time-series/chart-seed.ts +142 -0
  821. package/src/time-series/economic.ts +5 -0
  822. package/src/time-series/fundamentals.ts +18 -3
  823. package/src/time-series/history-acquisition.ts +499 -0
  824. package/src/time-series/leverage.ts +100 -0
  825. package/src/time-series/market-resolution.ts +4 -2
  826. package/src/time-series/market.ts +2 -1
  827. package/src/time-series/price-comparison.ts +175 -30
  828. package/src/time-series/range.ts +9 -1
  829. package/src/time-series/resolution.ts +174 -16
  830. package/src/time-series/resolve-context.ts +157 -0
  831. package/src/time-series/resolve.ts +126 -1577
  832. package/src/time-series/series-name.ts +38 -0
  833. package/src/time-series/series-presentation.ts +208 -0
  834. package/src/time-series/spec.ts +11 -6
  835. package/src/time-series/studies.ts +109 -12
  836. package/src/time-series/tail-reconcile.ts +121 -0
  837. package/src/time-series/types.ts +29 -2
  838. package/src/time-series/use-chart-resolution.ts +4 -5
  839. package/src/types/broker.ts +10 -0
  840. package/src/types/config.ts +14 -0
  841. package/src/types/data-provider.ts +14 -0
  842. package/src/types/exchange-rate.ts +6 -0
  843. package/src/types/financials.ts +104 -7
  844. package/src/types/headless.ts +76 -6
  845. package/src/types/instrument.ts +3 -0
  846. package/src/types/plugin.ts +65 -8
  847. package/src/types/price-history.ts +2 -0
  848. package/src/types/ticker.ts +13 -0
  849. package/src/types/trading.ts +59 -1
  850. package/src/ui/ascii-font.ts +13 -1
  851. package/src/ui/host.tsx +6 -1
  852. package/src/updater/command-names.ts +175 -0
  853. package/src/updater/index.ts +10 -5
  854. package/src/utils/calendar-date.ts +32 -15
  855. package/src/utils/cash-runway.ts +241 -0
  856. package/src/utils/central-banks.ts +42 -0
  857. package/src/utils/cli-output.ts +259 -80
  858. package/src/utils/contract-month.ts +16 -0
  859. package/src/utils/crypto-pair.ts +61 -3
  860. package/src/utils/currency-units.ts +29 -0
  861. package/src/utils/datetime-format.ts +10 -0
  862. package/src/utils/debug-log.ts +1 -1
  863. package/src/utils/decimal-comma.ts +39 -6
  864. package/src/utils/exchange-announcements.ts +71 -0
  865. package/src/utils/exchange-rate-snapshot.ts +10 -0
  866. package/src/utils/financial-statements.ts +83 -4
  867. package/src/utils/format.ts +34 -16
  868. package/src/utils/fundamentals.ts +150 -34
  869. package/src/utils/fx-market-hours.ts +10 -1
  870. package/src/utils/latest-financial-period.ts +8 -0
  871. package/src/utils/linux-libc.ts +54 -0
  872. package/src/utils/market-capitalization.ts +111 -15
  873. package/src/utils/max-drawdown.ts +64 -0
  874. package/src/utils/network-failure.ts +83 -0
  875. package/src/utils/option-expiry.ts +139 -7
  876. package/src/utils/price-earnings.ts +11 -5
  877. package/src/utils/price-history.ts +18 -8
  878. package/src/utils/price-window.ts +131 -0
  879. package/src/utils/release-date.ts +47 -0
  880. package/src/utils/sec.ts +3 -0
  881. package/src/utils/throttled-fetch.ts +11 -4
  882. package/src/utils/trailing-eps.ts +67 -0
  883. package/src/utils/typed-text.ts +21 -0
  884. package/src/utils/utc-time.ts +24 -1
  885. package/src/version.ts +6 -0
  886. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -0,0 +1,148 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { Box } from "../../../ui";
3
+ import {
4
+ DataTableView,
5
+ QueryBar,
6
+ StatGrid,
7
+ statGridRows,
8
+ usePaneFooter,
9
+ usePaneNoticeFooter,
10
+ useQueryBarSearch,
11
+ type DataTableColumn,
12
+ type StatItem,
13
+ } from "../../../components";
14
+ import { FILL_REST } from "../../../components/ui/fill";
15
+ import { usePaneRefreshKey } from "../../../components/data-table/table-pane";
16
+ import { useAsyncResource } from "../../../public/react";
17
+ import { isAccessDenied } from "../../../api-client/errors";
18
+ import type { ScreenDefinition } from "../../../api-client/equity-screener";
19
+ import { useThemeColors } from "../../../theme/theme-context";
20
+ import { fetchScreenCheck } from "./client";
21
+ import { checkRows, screenCheckSummary } from "./screen-check";
22
+
23
+ interface ScreenTickerCheckProps {
24
+ definition: ScreenDefinition;
25
+ snapshotId?: string;
26
+ width: number;
27
+ height: number;
28
+ focused: boolean;
29
+ fetcher?: typeof fetchScreenCheck;
30
+ }
31
+
32
+ /** A check keeps the screen's snapshot; streaming prices never change its decisions. */
33
+ export function ScreenTickerCheck({
34
+ definition,
35
+ snapshotId,
36
+ width,
37
+ height,
38
+ focused,
39
+ fetcher = fetchScreenCheck,
40
+ }: ScreenTickerCheckProps) {
41
+ const colors = useThemeColors();
42
+ const [draft, setDraft] = useState("");
43
+ const [ticker, setTicker] = useState<string | null>(null);
44
+ const search = useQueryBarSearch();
45
+ const controller = useRef<AbortController | null>(null);
46
+ const loader = useCallback(async () => {
47
+ controller.current?.abort();
48
+ const request = new AbortController();
49
+ controller.current = request;
50
+ return fetcher(definition, ticker!, snapshotId, request.signal);
51
+ }, [definition, fetcher, snapshotId, ticker]);
52
+ useEffect(() => () => controller.current?.abort(), [loader]);
53
+ useEffect(() => { search.focus(); }, [search.focus]);
54
+ const resource = useAsyncResource(ticker ? loader : null, { clearOnError: isAccessDenied });
55
+ const { data, loading, error } = resource;
56
+ const submit = (value: string) => {
57
+ const next = value.trim();
58
+ if (!next) return;
59
+ search.blur();
60
+ if (next === ticker) void resource.reload();
61
+ else setTicker(next);
62
+ };
63
+ usePaneRefreshKey(() => { void resource.reload(); }, { focused, enabled: !!ticker && !search.active });
64
+ usePaneFooter("equity-screener:check", () => ({
65
+ info: [
66
+ ...(loading ? [{ id: "loading", parts: [{ text: "checking ticker", tone: "muted" as const }] }] : []),
67
+ ...(data ? [{
68
+ id: "snapshot",
69
+ parts: [{ text: `snapshot ${data.snapshot.assembledAt.slice(0, 16).replace("T", " ")} UTC`, tone: "muted" as const }],
70
+ }] : []),
71
+ ],
72
+ hints: [{
73
+ id: "check",
74
+ key: "c",
75
+ label: "heck ticker",
76
+ onPress: () => submit(draft),
77
+ disabled: !draft.trim() || loading,
78
+ }],
79
+ }), [draft, ticker, loading, data, submit]);
80
+ usePaneNoticeFooter({
81
+ registrationId: "equity-screener:check-notices",
82
+ focused,
83
+ notices: [...(data?.warnings ?? []), ...(error ? [error] : [])],
84
+ });
85
+ const rows = data ? checkRows(data) : [];
86
+ const columns: DataTableColumn[] = [
87
+ { id: "criterion", label: "Criterion", width: Math.max(26, ...rows.map((row) => row.criterion.length)), flexGrow: 1, align: "left" },
88
+ { id: "value", label: "Value", width: Math.max(12, ...rows.map((row) => row.value.length)), align: "right" },
89
+ { id: "result", label: "Result", width: Math.max(6, ...rows.map((row) => row.result.length)), align: "left" },
90
+ { id: "asOf", label: "As of", width: Math.max(10, ...rows.map((row) => row.asOf.length)), align: "left" },
91
+ ...(rows.some((row) => row.state !== "available" && row.state !== "missing")
92
+ ? [{ id: "state", label: "Data", width: 12, align: "left" as const }]
93
+ : []),
94
+ ...(rows.some((row) => row.reason)
95
+ ? [{ id: "reason", label: "Reason", width: 30, align: "left" as const }]
96
+ : []),
97
+ ];
98
+ const stats: StatItem[] = data ? [
99
+ { label: "Listing", value: data.row ? `${data.row.symbol}:${data.row.exchange}` : data.symbol, detail: data.row?.name ?? undefined },
100
+ { label: "Result", value: screenCheckSummary(data), tone: data.matches === null ? "muted" : data.matches ? "positive" : "negative" },
101
+ ] : [];
102
+ return (
103
+ <Box width={width} flexDirection="column" {...FILL_REST}>
104
+ <QueryBar
105
+ width={width}
106
+ filters={[{
107
+ kind: "text",
108
+ id: "ticker",
109
+ label: "Ticker",
110
+ value: draft,
111
+ onChange: setDraft,
112
+ placeholder: "NVDA or NVDA:NASDAQ",
113
+ focused,
114
+ ...search.searchProps,
115
+ debounceMs: 0,
116
+ width: 24,
117
+ onSubmit: submit,
118
+ }]}
119
+ />
120
+ {data ? <StatGrid width={width} items={stats} /> : null}
121
+ <DataTableView
122
+ columns={columns}
123
+ items={rows}
124
+ getItemKey={(row) => row.id}
125
+ selection={{ kind: "none" }}
126
+ focused={focused && !search.active}
127
+ rootWidth={width}
128
+ rootHeight={Math.max(1, height - 1 - statGridRows(stats, width))}
129
+ status={{
130
+ loading: loading && !data,
131
+ error: !data ? error : null,
132
+ empty: !ticker,
133
+ subject: "ticker check",
134
+ emptyTitle: "Enter a ticker to check this screen.",
135
+ }}
136
+ renderCell={(row, column) => ({
137
+ text: column.id === "reason" ? row.reason ?? "--" : row[column.id as "criterion" | "value" | "result" | "asOf" | "state"],
138
+ color: column.id === "result"
139
+ ? row.passes === null ? colors.textMuted : row.passes ? colors.positive : colors.negative
140
+ : column.id === "reason" || column.id === "state" || column.id === "asOf" ? colors.textMuted : colors.text,
141
+ })}
142
+ sortColumnId={null}
143
+ sortDirection="asc"
144
+ emptyStateTitle="No criteria in this screen."
145
+ />
146
+ </Box>
147
+ );
148
+ }
@@ -1,5 +1,6 @@
1
1
  import type { HeadlessPaneDefinition } from "../../../types/plugin";
2
2
  import { explainRefusal } from "../shared/cloud-denied";
3
+ import { DATE_OPTION_EXAMPLES } from "../../../utils/calendar-date";
3
4
  import { fetchEstimates } from "./client";
4
5
  import { estimateRevisionsLockNote } from "./lock-note";
5
6
  import { estimateCurrent, periodLabel, pinnedEstimatePeriods } from "./model";
@@ -15,7 +16,7 @@ export const estimateRevisionsHeadless: HeadlessPaneDefinition<"bundle"> = {
15
16
  {
16
17
  key: "period",
17
18
  type: "string",
18
- description: "Optional fiscal end date, YYYY-MM-DD.",
19
+ description: `Optional fiscal end date, as ${DATE_OPTION_EXAMPLES}.`,
19
20
  settingKey: "period",
20
21
  },
21
22
  {
@@ -56,6 +57,7 @@ export const estimateRevisionsHeadless: HeadlessPaneDefinition<"bundle"> = {
56
57
  data.periods,
57
58
  args.options.period,
58
59
  args.options.frequency,
60
+ "--period",
59
61
  );
60
62
  return {
61
63
  sections: [
@@ -6,7 +6,7 @@ import { proLockNote, type FreeRoute } from "../shared/pro-lock-note";
6
6
 
7
7
  /** GUIDE's free preview, where it holds guidance for the company: Apple issues none, so GUIDE has no AAPL rows. */
8
8
  const GUIDE_ROUTE: FreeRoute = {
9
- text: (ticker, company) => `gloomberb fn GUIDE ${ticker} lists ${company}'s latest guidance ranges, with the date each was issued.`,
9
+ text: (ticker, company) => `gloom fn GUIDE ${ticker} lists ${company}'s latest guidance ranges, with the date each was issued.`,
10
10
  answers: async (symbol, context) => {
11
11
  const data = await fetchCompanyData("guidance", symbol, {}, context.apiClient, await resolveHeadlessIssuerListing(context, symbol), context.signal);
12
12
  return "guidance" in data && data.guidance.length + data.history.length > 0;
@@ -15,12 +15,12 @@ const GUIDE_ROUTE: FreeRoute = {
15
15
 
16
16
  /** The company's 8-Ks, where results and any guidance it gives are filed, for a company that files them. */
17
17
  const EIGHT_K_ROUTE: FreeRoute = {
18
- text: (ticker, company) => `gloomberb filings ${ticker} --form 8-K lists ${company}'s 8-Ks, where it files its results and any guidance, each with its items and a link to the filing.`,
18
+ text: (ticker, company) => `gloom filings ${ticker} --form 8-K lists ${company}'s 8-Ks, where it files its results and any guidance, each with its items and a link to the filing.`,
19
19
  answers: (symbol, context) => filesForm(symbol, "8-K", context),
20
20
  };
21
21
 
22
22
  const EARNINGS_ROUTE: FreeRoute = {
23
- text: (ticker, company) => `gloomberb earnings ${ticker} lists ${company}'s next report date with its consensus EPS estimate.`,
23
+ text: (ticker, company) => `gloom earnings ${ticker} lists ${company}'s next report date with its consensus EPS estimate.`,
24
24
  answers: async (symbol, context) => (await context.marketData.getEarningsCalendar?.([symbol]) ?? []).length > 0,
25
25
  };
26
26
 
@@ -4,6 +4,7 @@ import type {
4
4
  EstimateRevisionsPayload,
5
5
  } from "../../../api-client/estimate-revisions";
6
6
  import type { DataTableColumn } from "../../../components";
7
+ import { dateOptionError, readCalendarDate } from "../../../utils/calendar-date";
7
8
  export const estimateNumber = (value: number | null | undefined) =>
8
9
  value == null
9
10
  ? "--"
@@ -84,20 +85,17 @@ export function sortPeriods(
84
85
  });
85
86
  }
86
87
 
88
+ /** The periods ending on a fiscal end date, as a date option reads one; `option` is how a command line types it (`--period`). */
87
89
  export function pinnedEstimatePeriods(
88
90
  periods: EstimatePeriod[],
89
- periodEnd: unknown,
91
+ requestedEnd: unknown,
90
92
  frequency: unknown = "quarterly",
93
+ option = "",
91
94
  ): EstimatePeriod[] {
92
- if (periodEnd == null || periodEnd === "") return periods;
93
- if (
94
- typeof periodEnd !== "string" ||
95
- !/^\d{4}-\d{2}-\d{2}$/.test(periodEnd) ||
96
- !Number.isFinite(Date.parse(periodEnd)) ||
97
- new Date(periodEnd).toISOString().slice(0, 10) !== periodEnd
98
- ) {
99
- throw new Error("Fiscal end must be a valid YYYY-MM-DD date.");
100
- }
95
+ if (requestedEnd == null || requestedEnd === "") return periods;
96
+ const text = typeof requestedEnd === "string" ? requestedEnd.trim() : String(requestedEnd);
97
+ const periodEnd = readCalendarDate(text);
98
+ if (!periodEnd) throw new Error(dateOptionError(text, option, { subject: "a fiscal end date" }));
101
99
  if (frequency !== "quarterly" && frequency !== "annual")
102
100
  throw new Error("Frequency must be quarterly or annual.");
103
101
  const matches = periods.filter(
@@ -1,11 +1,12 @@
1
1
  import type { HeadlessPaneColumn, HeadlessPaneDefinition, HeadlessPaneRow } from "../../../types/plugin";
2
- import type { ExposureExtensionObservation, ExposurePayload, ExposureRequest } from "../../../api-client/exposure";
2
+ import type { ExposureExtensionObservation, ExposurePayload, ExposureRequest, ExposureScenario } from "../../../api-client/exposure";
3
3
  import { cliTerminalWidth } from "../../../utils/cli-output";
4
4
  import { clipToDisplayWidth, displayWidth } from "../../../utils/format";
5
5
  import { fiscalLabel } from "../company-kpis/model";
6
6
  import { humanLabel } from "../shared/research-cells";
7
+ import { freePreviewNote } from "../shared/free-preview";
7
8
  import { fetchExposure, fetchScenarios } from "./client";
8
- import { DEFAULT_SCENARIO, exposureCellText, parseCustomScenario, parseHoldings, pathRows, portfolioRows, scenarioTitle, tableRows, TABS, type ExposureRow } from "./model";
9
+ import { DEFAULT_SCENARIO, exposureCellText, LIBRARY_SCENARIO_IDS, parseCustomScenario, parseHoldings, pathRows, portfolioRows, scenarioTitle, tableRows, TABS, type ExposureRow } from "./model";
9
10
  import { portfolioHoldings, watchlistHoldings } from "./holdings";
10
11
  import { describeCollections, findNamedCollection } from "../../../portfolio/collection-name";
11
12
  import { driverAmount, driverRows, driverScope } from "./drivers";
@@ -183,6 +184,45 @@ function portfolioColumns(data: ExposurePayload, concentration: boolean, items:
183
184
 
184
185
  const CONCENTRATION_VIEWS = ["country", "supplier", "customer"] as const;
185
186
 
187
+ /** The server's own line about a preview ("Free preview covers the first holding at depth 1. ..."): what the view is, not what failed. */
188
+ const PREVIEW_NOTE = /^Free preview\b/i;
189
+
190
+ /**
191
+ * A free preview's Pro line in the words every report uses, and what the
192
+ * server says about the preview as a note: its first sentence is the Pro
193
+ * line's, the rest (how the totals are weighted) stays. The other unknowns
194
+ * are the report's errors.
195
+ */
196
+ function previewLines(data: Pick<ExposurePayload, "access" | "lockedHoldings" | "unknowns">): { lock: string[]; notes: string[]; unknowns: string[] } {
197
+ const preview = data.access === "preview";
198
+ const notes = preview ? data.unknowns.filter(line => PREVIEW_NOTE.test(line))
199
+ .map(line => line.replace(/^Free preview[^.]*\.\s*/i, "").trim()).filter(Boolean) : [];
200
+ const others = preview ? data.unknowns.filter(line => !PREVIEW_NOTE.test(line)) : data.unknowns;
201
+ const lock = preview ? [freePreviewNote({ shows: "the first holding, one relationship hop deep",
202
+ adds: `${data.lockedHoldings === 1 ? "the other holding and " : data.lockedHoldings > 1 ? `the other ${data.lockedHoldings} holdings and ` : ""}paths up to four hops` })] : [];
203
+ return { lock, notes, unknowns: others };
204
+ }
205
+
206
+ /** Library ids as a list: `a, b or c`. */
207
+ function scenarioIds(library: readonly ExposureScenario[]): string {
208
+ const ids = library.flatMap(s => s.id ? [s.id] : []);
209
+ return ids.length > 1 ? `${ids.slice(0, -1).join(", ")} or ${ids.at(-1)}` : ids[0] ?? "";
210
+ }
211
+
212
+ /** An id the library does not have: the ids it does, the one it was likely meant for (`rates` for rates-up), and --custom. */
213
+ function unknownScenarioMessage(id: string, library: readonly ExposureScenario[]): string {
214
+ const typed = id.trim().toLowerCase();
215
+ const near = typed ? library.filter(s => s.id?.split("-").includes(typed) || s.id?.startsWith(typed)) : [];
216
+ return [`Unknown scenario: ${id}.`, ...(near.length === 1 ? [`Did you mean ${near[0]!.id}?`] : []),
217
+ ...(library.length ? [`Scenarios: ${scenarioIds(library)}.`] : []), "Or describe your own with --custom."].join(" ");
218
+ }
219
+
220
+ /** The note a report run on the default scenario carries: which one it is, and how to pick another. */
221
+ function defaultScenarioNote(scenario: ExposureScenario, library: readonly ExposureScenario[]): string {
222
+ const others = library.filter(s => s.id !== scenario.id);
223
+ return `${scenario.label} (${scenario.id}) is the default scenario. Pick another with --scenario${others.length ? ` (${scenarioIds(others)})` : ""}, or describe your own with --custom.`;
224
+ }
225
+
186
226
  export const exposureHeadless: HeadlessPaneDefinition<"bundle"> = {
187
227
  shape: "bundle",
188
228
  freshness: { status: "not-a-feed", basis: "company disclosures" },
@@ -190,7 +230,8 @@ export const exposureHeadless: HeadlessPaneDefinition<"bundle"> = {
190
230
  discovery: { aliases: ["EXPO"], dataRequirements: ["Gloom Cloud geographic revenue, disclosed supply chains, KPIs, guidance and credit disclosures", "Portfolio NAV for local PORT weights"],
191
231
  limitations: ["Pro: full holdings and up to four-hop paths; free: one holding, one hop.", "Operating exposure estimates, never predicted stock returns.", "Missing relationships and sensitivities remain unknown.", "Basis and reporting period are kept separate."] },
192
232
  options: [
193
- { key: "scenario", type: "string", settingKey: "scenario", defaultValue: "taiwan-disruption", description: "Library scenario id, or use --custom." },
233
+ { key: "scenario", type: "string", settingKey: "scenario", defaultValue: DEFAULT_SCENARIO.id!, values: LIBRARY_SCENARIO_IDS.map(value => ({ value })),
234
+ description: "Library scenario id, or use --custom." },
194
235
  { key: "custom", type: "string", settingKey: "customScenario", description: "JSON scenario with label and shocks; supports multiple shocks and explicit transmission assumptions." },
195
236
  { key: "depth", type: "integer", settingKey: "depth", defaultValue: 2, minimum: 1, maximum: 4, description: "Maximum relationship hops." },
196
237
  { key: "nav", type: "string", settingKey: "nav", description: "Positive portfolio NAV in its configured currency; required for PORT." },
@@ -217,8 +258,9 @@ export const exposureHeadless: HeadlessPaneDefinition<"bundle"> = {
217
258
  holdings = watchlistHoldings(tickers, findNamedCollection(ctx.config.watchlists, source[2])?.id ?? source[2]!);
218
259
  } else holdings = parseHoldings(input);
219
260
  const id = String(args.options.scenario ?? DEFAULT_SCENARIO.id);
220
- const scenario = args.options.custom ? parseCustomScenario(String(args.options.custom)) : (await fetchScenarios(ctx.apiClient)).find(s => s.id === id);
221
- if (!scenario) throw new Error(`Unknown scenario: ${id}`);
261
+ const library = args.options.custom ? [] : await fetchScenarios(ctx.apiClient);
262
+ const scenario = args.options.custom ? parseCustomScenario(String(args.options.custom)) : library.find(s => s.id === id);
263
+ if (!scenario) throw new Error(unknownScenarioMessage(id, library));
222
264
  const cashWeight = args.options.cash === undefined ? undefined : Number(args.options.cash);
223
265
  if (cashWeight !== undefined && (!Number.isFinite(cashWeight) || Math.abs(cashWeight) > 10)) throw new Error("Cash must be a NAV fraction between -10 and 10.");
224
266
  if (ctx.signal.aborted) throw new Error("Exposure analysis cancelled.");
@@ -227,8 +269,11 @@ export const exposureHeadless: HeadlessPaneDefinition<"bundle"> = {
227
269
  const stress = withNotes(portfolioRows(data, "stress"), row => row.incomplete ? row.unknowns : []);
228
270
  const concentrations = CONCENTRATION_VIEWS.flatMap(kind => portfolioRows(data, kind).map(row => ({ ...row, kind })));
229
271
  const holdingRows = tableRows(data), paths = pathRows(data);
272
+ const preview = previewLines(data);
273
+ // The library's first scenario runs unless another is asked for: the report says so, and what else there is.
274
+ const notes = [...(!args.options.custom && scenario.id === DEFAULT_SCENARIO.id ? [defaultScenarioNote(scenario, library)] : []), ...preview.notes];
230
275
  return { complete: data.lockedHoldings === 0 && data.holdings.every(h => h.status === "quantified") && data.unknowns.length === 0,
231
- errors: [...data.unknowns, ...(data.access === "preview" ? ["Free preview: one holding, depth one. Full analysis requires Pro."] : [])],
276
+ errors: [...preview.lock, ...preview.unknowns], ...(notes.length ? { notes } : {}),
232
277
  sections: [
233
278
  { title: "Holdings", rows: data.holdings.map(h => ({ symbol: h.symbol, weight: h.weight, status: h.status, measures: h.measures, coverage: h.coverage, unknowns: h.unknowns })),
234
279
  textColumns: fitted(holdingColumns(data), holdingRows), textRows: textRows(holdingRows) },
@@ -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
  };
@@ -3,6 +3,13 @@ import { humanLabel } from "../shared/research-cells";
3
3
 
4
4
  export const TABS = [{ value: "table", label: "Table" }, { value: "drivers", label: "Drivers" }, { value: "paths", label: "Paths" }, { value: "portfolio", label: "Portfolio" }];
5
5
  export const DEFAULT_SCENARIO: ExposureScenario = { id: "taiwan-disruption", label: "Taiwan disruption", shocks: [{ id: "taiwan", kind: "country", target: "TW", changePct: -100 }] };
6
+ /**
7
+ * The ids of Gloom Cloud's scenario library, which the catalog lists for
8
+ * `--scenario`. A report reads the library itself, so an id added there runs
9
+ * before it is listed here.
10
+ */
11
+ export const LIBRARY_SCENARIO_IDS = ["taiwan-disruption", "china-demand", "europe-demand", "china-semiconductor-ban", "china-tariff",
12
+ "oil-up", "rates-up", "usd-up", "tsmc-outage", "microsoft-capex"] as const;
6
13
  export const basisLabel = (basis: string | null) => basis?.replaceAll("_", " ") ?? "Unknown basis";
7
14
  const pct = (value: number) => `${value.toFixed(1)}%`;
8
15
  export const rangeText = (range: ExposureRange | null) => !range ? "Unknown" : range.low === range.high ? pct(range.low) : `${range.low.toFixed(1)} to ${range.high.toFixed(1)}%`;
@@ -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";
@@ -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.
@@ -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
  });
@@ -4,6 +4,7 @@ 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";
7
8
  import type { FuturesReturnHorizon } from "./returns";
8
9
  import type { FuturesTermsMap } from "./use-board-terms";
9
10
  import type { FrontReturnsMap } from "./use-front-returns";
@@ -41,20 +42,20 @@ export function futuresRowId(row: FuturesTableRow): string {
41
42
  return row.type === "header" ? `header-${row.sector}` : row.contract.symbol;
42
43
  }
43
44
 
44
- /** "Nov 26" or "Futures,Nov-2026"; a hyphen takes only a whole year, since "Futures,Nov-20" is 2026 cut short. */
45
+ /** "Nov 2026", "Nov 26" or "Futures,Nov-2026"; a hyphen takes only a whole year, since "Futures,Nov-20" is 2026 cut short. */
45
46
  const CONTRACT_MONTH = /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(?: (\d{4}|\d{2})|-(\d{4}))$/i;
46
47
 
47
48
  /**
48
49
  * The alias stays the row identity while its quoted contract rolls, so the
49
50
  * 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.
51
+ * Dec 2026"). Quote names arrive as "Crude Oil Nov 2026", "Crude Oil Nov 26",
52
+ * "Corn Futures,Dec-2026" or cut off mid-month ("Futures,Dec-"); a month
53
+ * without a year is dropped rather than guessed.
53
54
  */
54
55
  export function futuresContractName(contract: FuturesContract, quote?: Quote | null): string {
55
56
  const month = quotedContractMonth(contract, quote);
56
57
  if (!month) return contract.name;
57
- return `${contract.name} ${MONTH_NAMES[month.month]} ${String(month.year).slice(-2)}`;
58
+ return `${contract.name} ${contractMonthLabel(month.year, month.month)}`;
58
59
  }
59
60
 
60
61
  const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
@@ -82,9 +83,9 @@ function dayMonth(date: string): string {
82
83
  * The row's headline: the contract its quote prices, as futuresContractName
83
84
  * words it: the root's front month until its roll date. Two notes follow,
84
85
  * 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,
86
+ * nearer month still trades, that month's last trade: "WTI Crude Oil Dec 2026,
86
87
  * 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
88
+ * that month: "WTI Crude Oil Nov 2026, Dec most active". The terms only add a
88
89
  * note when they name the month the quote prices, so a roll between the two
89
90
  * loads never mixes months, and place the month when the quote's name carries
90
91
  * none. A name column too narrow for a note drops it, the last one first.
@@ -104,7 +105,7 @@ export function futuresContractHeadline(
104
105
  const month = agree ? quoted ?? termsMonth : quoted;
105
106
  if (!month) return contract.name;
106
107
  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)}`;
108
+ const plain = `${contract.name} ${contractMonthLabel(month.year, month.month)}`;
108
109
  if (!agree) return plain;
109
110
  const notes: Array<{ text: string; min: string }> = [];
110
111
  const nearest = terms?.nearest;
@@ -117,7 +118,7 @@ export function futuresContractHeadline(
117
118
  if (active && /^\d{4}-\d{2}$/.test(active.deliveryMonth) && active.deliveryMonth !== priced) {
118
119
  // Another year's month says which year it is.
119
120
  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)}`;
121
+ const label = active.deliveryMonth.slice(0, 4) === String(month.year) ? name : `${name} ${active.deliveryMonth.slice(0, 4)}`;
121
122
  notes.push({ text: `, ${label} most active`, min: `, ${label} most active` });
122
123
  }
123
124
  // The month the quote prices leads, so a column that clips the tail still shows it; a note keeps its place
@@ -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
  }
@@ -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,