gloomberb 0.18.2 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (954) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -9,7 +9,11 @@ import {
9
9
  type ManualChartResolution,
10
10
  } from "../../../../time-series/resolution";
11
11
  import type { PricePoint } from "../../../../types/financials";
12
- import { isAlwaysOpenExchange, isRegularSessionTime, latestRegularSessionClose } from "../../../../market-data/market/freshness";
12
+ import { isAlwaysOpenExchange, isRegularSessionTime, latestRegularSessionClose, sessionCalendarTimeZone } from "../../../../market-data/market/freshness";
13
+ import { barLastSession } from "../../../../market-data/market/bar-period";
14
+ import {
15
+ barCloseDay, barSessionDay, isIntradayDailyBar, isReturnPeriod, periodBaseDay, periodBaseIndex,
16
+ } from "../../../../market-data/market/period-return";
13
17
  import { isRoundTheClockCoin } from "../../../../utils/crypto-pair";
14
18
  import { currentFxClosureStart, isCurrencyPairListing } from "../../../../utils/fx-market-hours";
15
19
  import { pricePointValues } from "../../../../utils/price-history-integrity";
@@ -49,12 +53,56 @@ export function returnWindowStart(range: ReturnRange, end: number): number {
49
53
  return subtractTimeRange(new Date(end), range).getTime();
50
54
  }
51
55
 
56
+ const utcDay = (time: number) => new Date(time).toISOString().slice(0, 10);
57
+
58
+ /** The session date of `time` at a venue, on its clock; the UTC date where its sessions are unknown. */
59
+ function venueDay(time: number, venue: string | undefined): string {
60
+ const zone = venue ? sessionCalendarTimeZone(venue) : null;
61
+ return zone ? zonedDateKey(time, zone) : utcDay(time);
62
+ }
63
+
64
+ /**
65
+ * The calendar date a 1W to 5Y window ending at `end` is measured from, the
66
+ * close on or before which is the base of its returns (periodBaseDay), as CMP
67
+ * and every period return measure it: 1M ending Wed 21 Oct is from Mon 21
68
+ * Sep's close. Null for 6H, 1D and 5D, which are spans of time, and ALL.
69
+ */
70
+ export function returnBaseDay(range: ReturnRange, end: number, venue?: string): string | null {
71
+ return isReturnPeriod(range) ? periodBaseDay(venueDay(end, venue), range) : null;
72
+ }
73
+
74
+ /**
75
+ * Where the rows after a base day start, exclusive: past the base day's
76
+ * session close for intraday bars, and before the first bar whose close is
77
+ * from after it for daily (stamped by their date at midnight UTC), weekly
78
+ * and monthly ones (stamped by their period's first day, barCloseDay). For
79
+ * daily and longer bars this is what a request reaches back from; the rows
80
+ * start where returnRowsFrom finds the base among the loaded bars.
81
+ */
82
+ function afterBaseDay(baseDay: string, resolution: ManualChartResolution, venue: string | undefined): number {
83
+ const nextDay = Date.parse(`${baseDay}T00:00:00Z`) + DAY_MS;
84
+ if (isIntradayResolution(resolution)) {
85
+ // Midnight UTC after the base day is past every venue's close of it and before its next one.
86
+ const close = venue ? latestRegularSessionClose(venue, nextDay) : null;
87
+ return close && close.date <= baseDay ? close.close - 1 : nextDay - 1;
88
+ }
89
+ for (let day = nextDay - 40 * DAY_MS; day <= nextDay; day += DAY_MS) {
90
+ if (barCloseDay(utcDay(day), resolution, venue) > baseDay) return day - 1;
91
+ }
92
+ return nextDay - 1;
93
+ }
94
+
52
95
  /**
53
- * Where the rows start, exclusive: the window's start for intraday bars. A
54
- * daily or longer bar is stamped with its date at midnight UTC, so the window
55
- * takes every bar from its start date on.
96
+ * Where the rows start, exclusive, before the bars are loaded: what the
97
+ * request reaches back from. A 1W to 5Y window starts after its base day
98
+ * (returnBaseDay), so the close on or before it is the bar before the rows
99
+ * and the base of every return. Otherwise the window's start for intraday
100
+ * bars; a daily or longer bar is stamped with its date at midnight UTC, so
101
+ * the window takes every bar from its start date on.
56
102
  */
57
- export function returnVisibleFrom(range: ReturnRange, resolution: ManualChartResolution, end: number): number {
103
+ export function returnVisibleFrom(range: ReturnRange, resolution: ManualChartResolution, end: number, venue?: string): number {
104
+ const baseDay = returnBaseDay(range, end, venue);
105
+ if (baseDay) return afterBaseDay(baseDay, resolution, venue);
58
106
  const start = returnWindowStart(range, end);
59
107
  if (isIntradayResolution(resolution)) return start;
60
108
  const day = new Date(start);
@@ -62,6 +110,31 @@ export function returnVisibleFrom(range: ReturnRange, resolution: ManualChartRes
62
110
  return day.getTime() - 1;
63
111
  }
64
112
 
113
+ /**
114
+ * Where the rows start among the loaded bars, exclusive. A 1W to 5Y window
115
+ * of daily or longer bars starts after the bar on or before its base day,
116
+ * each bar dated by its session day (barSessionDay; a week or month by the
117
+ * day it closes), so that close is the bar before the rows however the feed
118
+ * stamps it: a JPX bar at 00:00 JST is 15:00 UTC the day before. Without a
119
+ * bar on or before the base day, every bar is a row. Otherwise
120
+ * returnVisibleFrom.
121
+ */
122
+ export function returnRowsFrom(
123
+ points: readonly PricePoint[],
124
+ range: ReturnRange,
125
+ resolution: ManualChartResolution,
126
+ end: number,
127
+ venue?: string,
128
+ ): number {
129
+ const estimate = returnVisibleFrom(range, resolution, end, venue);
130
+ const baseDay = returnBaseDay(range, end, venue);
131
+ const bars = toBars(points);
132
+ if (!baseDay || isIntradayResolution(resolution) || !bars.length) return estimate;
133
+ const days = bars.map((bar) => barCloseDay(barSessionDay(bar.timestamp, venue), resolution, venue));
134
+ const index = periodBaseIndex(days, baseDay, Number.POSITIVE_INFINITY);
135
+ return index < 0 ? bars[0]!.timestamp - 1 : bars[index]!.timestamp;
136
+ }
137
+
65
138
  /**
66
139
  * These windows are shorter than a closed market's gap, so they also end at
67
140
  * the latest bar when it is earlier: a venue whose sessions the app does not
@@ -120,6 +193,11 @@ function lookbackDays(resolution: ManualChartResolution): number {
120
193
  return 62;
121
194
  }
122
195
 
196
+ /** How far before a dated window (`--from`) the request reaches for the bar before it: a weekend and a holiday. */
197
+ export function returnWindowLookbackMs(resolution: ManualChartResolution): number {
198
+ return lookbackDays(resolution) * DAY_MS;
199
+ }
200
+
123
201
  /**
124
202
  * How far before the window the request reaches. The bar just before the
125
203
  * window is the base of every return, so the request covers a weekend or
@@ -245,6 +323,35 @@ export function buildReturnRows(
245
323
  return rows.reverse();
246
324
  }
247
325
 
326
+ /**
327
+ * The session day of the close every return of a window is measured from
328
+ * (buildReturnRows' base): the bar before its rows, else its first priced
329
+ * bar. A daily bar's date, a weekly or monthly bar's last session, an
330
+ * intraday bar's session date at its venue. Null for a window without rows.
331
+ */
332
+ export function returnBaseCloseDay(
333
+ points: readonly PricePoint[],
334
+ visibleFrom: number,
335
+ resolution: ManualChartResolution,
336
+ venue: string | undefined,
337
+ now: number,
338
+ ): string | null {
339
+ const bars = toBars(points);
340
+ const first = bars.findIndex((bar) => bar.timestamp > visibleFrom);
341
+ if (first < 0) return null;
342
+ const base = first > 0 && bars[first - 1]!.close !== null ? bars[first - 1] : bars.slice(first).find((bar) => bar.close !== null);
343
+ if (!base) return null;
344
+ if (isIntradayResolution(resolution)) return venueDay(base.timestamp, venue);
345
+ const day = barSessionDay(base.timestamp, venue);
346
+ const period = resolution === "1wk" ? "week" : resolution === "1mo" ? "month" : null;
347
+ return period ? barLastSession(day, period, venue, now) ?? barCloseDay(day, resolution, venue) : day;
348
+ }
349
+
350
+ /** Whether the newest daily row is the session still trading at its venue, which its table marks. */
351
+ export function isTodayReturnRow(row: Pick<ReturnRow, "timestamp"> | undefined, resolution: ManualChartResolution, venue: string | undefined, now: number): boolean {
352
+ return !!row && resolution === "1d" && isIntradayDailyBar(barSessionDay(row.timestamp, venue), venue, now);
353
+ }
354
+
248
355
  /** The latest bar time in a loaded history, or null when it has none. */
249
356
  export function latestBarTime(points: readonly PricePoint[]): number | null {
250
357
  let latest: number | null = null;
@@ -37,12 +37,16 @@ import {
37
37
  buildReturnRows,
38
38
  closedMarketNote,
39
39
  effectiveReturnResolution,
40
+ isTodayReturnRow,
41
+ returnBaseCloseDay,
40
42
  RETURN_RANGES,
41
43
  type ReturnRange,
42
44
  type ReturnRow,
43
45
  } from "./returns-model";
44
46
  import { loadReturnSeries, type ReturnSeries } from "./returns-history";
45
47
  import { formingHistoryBar, formingHistoryBarText, historyBarDate } from "./history-bars";
48
+ import { periodBaseText } from "../../../../market-data/market/period-return";
49
+ import { DAY_SO_FAR_TEXT } from "../../../../time-series/session-bar";
46
50
 
47
51
  type ReturnColumnId = "time" | "price" | "intervalChange" | "intervalPercent" | "cumulativeChange" | "cumulativePercent";
48
52
  type ReturnColumn = DataTableColumn & { id: ReturnColumnId };
@@ -192,15 +196,24 @@ export function ReturnsPane({ focused, width, height }: PaneProps) {
192
196
  () => data ? formingHistoryBar(data.resolution, newestDate, data.venue || undefined, Date.now()) : null,
193
197
  [data, newestDate],
194
198
  );
195
- const formingKey = forming ? returnRows[0]?.key : undefined;
199
+ // Today's daily bar is the session still trading, marked as Historical Prices marks it.
200
+ const dayToDate = !!data && isTodayReturnRow(returnRows[0], data.resolution, data.venue || undefined, Date.now());
201
+ const formingKey = forming || dayToDate ? returnRows[0]?.key : undefined;
196
202
  const barSize = data?.resolution ?? shownResolution;
203
+ // The close every total is measured from: `from Mon 21 Sep close`.
204
+ const baseText = useMemo(() => {
205
+ const day = data && returnRows.length ? returnBaseCloseDay(data.points, data.visibleFrom, data.resolution, data.venue || undefined, Date.now()) : null;
206
+ return day ? periodBaseText(day) : null;
207
+ }, [data, returnRows.length]);
197
208
  // A shut market's window ends at its last session, which the footer names.
198
209
  const marketInfo = useMemo<PaneFooterSegment[]>(() => [
210
+ ...baseText ? [{ id: "base", parts: [{ text: baseText, tone: "muted" as const }] }] : [],
199
211
  ...data?.lastSession
200
212
  ? [{ id: "market", parts: [{ text: closedMarketNote(data.lastSession, data.visibleTo), tone: "muted" as const }] }]
201
213
  : [],
202
214
  ...forming && newestDate ? [{ id: "forming", parts: [{ text: formingHistoryBarText(forming, newestDate), tone: "muted" as const }] }] : [],
203
- ], [data, forming, newestDate]);
215
+ ...dayToDate ? [{ id: "forming", parts: [{ text: DAY_SO_FAR_TEXT, tone: "muted" as const }] }] : [],
216
+ ], [baseText, data, dayToDate, forming, newestDate]);
204
217
  usePaneStatusFooter({ registrationId: "returns", loading, error, hints, info: marketInfo });
205
218
 
206
219
  const integrityNotice = priceHistoryIntegrityNotice(returnRows.filter((row) => row.inconsistent).length);
@@ -288,6 +301,8 @@ export function ReturnsPane({ focused, width, height }: PaneProps) {
288
301
  ["Range", data?.range ?? range],
289
302
  ["Interval", getChartResolutionLabel(data?.resolution ?? shownResolution)],
290
303
  ...(forming && newestDate ? [["Partial bar", `${newestDate}, ${formingHistoryBarText(forming, newestDate)}`]] : []),
304
+ ...(dayToDate && newestDate ? [["Partial bar", `${newestDate}, ${DAY_SO_FAR_TEXT}`]] : []),
305
+ ...(baseText ? [["Base", baseText]] : []),
291
306
  ["Window", data ? `after ${new Date(data.visibleFrom).toISOString()} through ${new Date(data.visibleTo).toISOString()}` : ""],
292
307
  ...(data?.lastSession ? [["Market", closedMarketNote(data.lastSession, data.visibleTo)]] : []),
293
308
  ["Time zone", "UTC, bar open"],
@@ -1,6 +1,7 @@
1
1
  import type { EarningsField, FinancialStatement } from "../../../../types/financials";
2
2
  import { completeAvailability, statementFieldAvailability } from "../../../../utils/financial-statements";
3
3
  import { hasStatementGap } from "../../../../utils/statement-gaps";
4
+ import { trailingEpsAcrossFiscalYearEnd } from "../../../../utils/trailing-eps";
4
5
 
5
6
  export type FinancialPeriod = "annual" | "quarterly";
6
7
 
@@ -159,6 +160,8 @@ const BALANCE_KEYS = new Set<string>([
159
160
  function aggregateQuarterlyStatements(
160
161
  statements: FinancialStatement[],
161
162
  date: string,
163
+ /** Every quarter and fiscal year on file, for EPS across a fiscal Q4 that reports none. */
164
+ onFile: { quarterly: readonly FinancialStatement[]; annual: readonly FinancialStatement[] } = { quarterly: [], annual: [] },
162
165
  ): FinancialTableStatement | null {
163
166
  if (statements.length !== 4) return null;
164
167
  // A provider may return semiannual reports or skip a quarter. Four rows do
@@ -215,6 +218,11 @@ function aggregateQuarterlyStatements(
215
218
  if (values.length === 4) {
216
219
  (aggregate as unknown as Record<string, unknown>)[key] = values.reduce((left, right) => left + right, 0);
217
220
  retainAvailability(key, statements);
221
+ } else if (key === "eps" || key === "basicEps") {
222
+ const acrossYearEnd = trailingEpsAcrossFiscalYearEnd(statements, onFile.quarterly, onFile.annual, key);
223
+ if (!acrossYearEnd) continue;
224
+ aggregate[key] = acrossYearEnd.value;
225
+ retainAvailability(key, acrossYearEnd.inputs);
218
226
  }
219
227
  }
220
228
 
@@ -252,18 +260,24 @@ function aggregateQuarterlyStatements(
252
260
  * reads a flow over a year from. Null when fewer than four consecutive
253
261
  * quarters end there.
254
262
  */
255
- export function trailingFourQuarters(quarterlyStatements: readonly FinancialStatement[], end: string) {
263
+ export function trailingFourQuarters(
264
+ quarterlyStatements: readonly FinancialStatement[],
265
+ end: string,
266
+ annualStatements: readonly FinancialStatement[] = [],
267
+ ) {
256
268
  const sorted = [...quarterlyStatements].sort((a, b) => a.date.localeCompare(b.date));
257
269
  const index = sorted.findIndex((statement) => statement.date === end);
258
- return index < 3 ? null : aggregateQuarterlyStatements(sorted.slice(index - 3, index + 1), "TTM");
270
+ return index < 3 ? null : aggregateQuarterlyStatements(sorted.slice(index - 3, index + 1), "TTM", { quarterly: sorted, annual: annualStatements });
259
271
  }
260
272
 
261
- export function computeTTM(quarterlyStatements: FinancialStatement[]) {
262
- return aggregateQuarterlyStatements([...quarterlyStatements].sort((a, b) => a.date.localeCompare(b.date)).slice(-4), "TTM");
273
+ export function computeTTM(quarterlyStatements: FinancialStatement[], annualStatements: readonly FinancialStatement[] = []) {
274
+ const sorted = [...quarterlyStatements].sort((a, b) => a.date.localeCompare(b.date));
275
+ return aggregateQuarterlyStatements(sorted.slice(-4), "TTM", { quarterly: sorted, annual: annualStatements });
263
276
  }
264
277
 
265
- function computePreviousTtm(quarterlyStatements: FinancialStatement[]) {
266
- return aggregateQuarterlyStatements([...quarterlyStatements].sort((a, b) => a.date.localeCompare(b.date)).slice(-8, -4), "prevTTM");
278
+ function computePreviousTtm(quarterlyStatements: FinancialStatement[], annualStatements: readonly FinancialStatement[]) {
279
+ const sorted = [...quarterlyStatements].sort((a, b) => a.date.localeCompare(b.date));
280
+ return aggregateQuarterlyStatements(sorted.slice(-8, -4), "prevTTM", { quarterly: sorted, annual: annualStatements });
267
281
  }
268
282
 
269
283
  export function buildPreviousStatementMap(
@@ -295,7 +309,7 @@ export function buildPreviousStatementMap(
295
309
  }
296
310
 
297
311
  if (ttm) {
298
- const previousTtm = computePreviousTtm(quarterlyStatements);
312
+ const previousTtm = computePreviousTtm(quarterlyStatements, annualStatements);
299
313
  const latest = quarterlyStatements.at(-1);
300
314
  const prior = quarterlyStatements.at(-5);
301
315
  const days = latest && prior ? (Date.parse(latest.date) - Date.parse(prior.date)) / 86_400_000 : NaN;
@@ -123,6 +123,8 @@ export function canCompareFinancialRow(
123
123
  ): boolean {
124
124
  if (!previous) return false;
125
125
  const key = row.kind === "group" ? row.summaryKey : row.key;
126
+ // A line filled from the exchange is not compared with the statements source's: the two define revenue differently.
127
+ if (key && filledLine(current, key) !== filledLine(previous, key)) return false;
126
128
  const sameShareBasis = current.shareBasis === previous.shareBasis;
127
129
  if (key && SHARE_COUNT_FIELDS.has(key)) return sameShareBasis;
128
130
  if (key && PER_SHARE_EARNINGS_FIELDS.has(key) && !sameShareBasis) return false;
@@ -131,6 +133,10 @@ export function canCompareFinancialRow(
131
133
  return !!currentCurrency && currentCurrency === previousCurrency;
132
134
  }
133
135
 
136
+ function filledLine(statement: FinancialStatement, key: keyof FinancialStatement): boolean {
137
+ return statement.filledFrom?.fields.some((field) => field === key) === true;
138
+ }
139
+
134
140
  export function semanticGrowthValue(
135
141
  growth: number | undefined,
136
142
  direction: FinancialGrowthDirection,
@@ -513,7 +519,7 @@ export function selectFinancialStatements(
513
519
  .filter((candidate) => !tabRows || tabRows.some((row) => hasFinancialRowValue(row, [candidate])))
514
520
  .slice(-limit)
515
521
  .reverse();
516
- const trailing = period === "annual" && statement !== "balance" ? computeTTM(quarterlyStatements) : null;
522
+ const trailing = period === "annual" && statement !== "balance" ? computeTTM(quarterlyStatements, annualStatements) : null;
517
523
  // Right after a fiscal year closes, the last four quarters are that year:
518
524
  // the reported year is shown, not a second column of the same period.
519
525
  const ttm = trailing && !coversLatestYear(trailing, rawStatements[0]) ? trailing : null;
@@ -606,3 +612,32 @@ export function buildFinancialTableModel(
606
612
 
607
613
  return { period, subTab, statements, rows, unit };
608
614
  }
615
+
616
+ /**
617
+ * A statement table's columns for stalePeriodNote, each with whether the
618
+ * statement's lead line (its first: revenue, total assets, free cash flow)
619
+ * has a figure in it, so a newer column with only some figures (an EPS
620
+ * alone) is not read as the latest period.
621
+ */
622
+ export function financialStatementPeriods(
623
+ statements: readonly FinancialTableStatement[],
624
+ subTab: Pick<FinancialSubTab, "rows">,
625
+ ): Array<{ date: string; lead: boolean }> {
626
+ const lead = subTab.rows[0];
627
+ return statements.map((statement) => ({ date: statement.date, lead: !!lead && hasFinancialRowValue(lead, [statement]) }));
628
+ }
629
+
630
+ /** The statement lines a table has a row for (filledPeriodsNote), group totals included. */
631
+ export function financialSubTabFields(subTab: Pick<FinancialSubTab, "rows">): Set<string> {
632
+ const fields = new Set<string>();
633
+ const visit = (rows: readonly FinancialRowDef[]) => {
634
+ for (const row of rows) {
635
+ if (isFinancialGroup(row)) {
636
+ if (row.summaryKey) fields.add(row.summaryKey);
637
+ visit(row.children);
638
+ } else if (row.key) fields.add(row.key);
639
+ }
640
+ };
641
+ visit(subTab.rows);
642
+ return fields;
643
+ }
@@ -0,0 +1,56 @@
1
+ import { useCallback, useMemo } from "react";
2
+ import { apiClient } from "../../../../api-client";
3
+ import { createPluginCache } from "../../../../data/plugin-cache";
4
+ import { useAsyncResource } from "../../../../public/react";
5
+ import type { TickerFinancials } from "../../../../types/financials";
6
+ import { fetchOfferingFilings, offeringNote, offeringsAfter, type OfferingFiling } from "../../../../utils/cash-runway";
7
+ import { latestFinancialPeriod } from "../../../../utils/latest-financial-period";
8
+ import { nonUsSecListingVenue } from "../../../../utils/sec";
9
+ import { cachedCloudResource, loadCloudResource } from "../../shared/cloud-resource";
10
+
11
+ /** A prospectus is filed days before the cash lands; an hour-old list is recent enough for the note. */
12
+ export const offeringFilingsCache = createPluginCache<OfferingFiling[]>({
13
+ kind: "offering-filings", source: "gloom-cloud", schemaVersion: 1,
14
+ policy: { staleMs: 60 * 60_000, expireMs: 7 * 24 * 60 * 60_000 },
15
+ });
16
+
17
+ /** The newest balance sheet the statements carry: the latest quarter's, or the latest year's without quarters. */
18
+ export function latestBalanceSheetDate(financials: Pick<TickerFinancials, "annualStatements" | "quarterlyStatements"> | null | undefined): string | null {
19
+ const latest = latestFinancialPeriod([...financials?.quarterlyStatements ?? [], ...financials?.annualStatements ?? []], (row) => row.date);
20
+ return latest?.date ?? null;
21
+ }
22
+
23
+ /** Offering prospectuses for a US company; a listing abroad files none of these. */
24
+ function offeringSymbol(symbol: string | null | undefined, exchange: string | undefined): string | null {
25
+ const key = symbol?.trim().toUpperCase();
26
+ return key && !nonUsSecListingVenue(key, exchange) ? key : null;
27
+ }
28
+
29
+ /** The note that an offering filed after `periodEnd` is not in the cash yet, for a report. A failed read leaves it out. */
30
+ export async function loadOfferingNote(
31
+ client: Parameters<typeof fetchOfferingFilings>[0],
32
+ listing: { symbol: string; exchange?: string },
33
+ periodEnd: string | null,
34
+ signal?: AbortSignal,
35
+ ): Promise<string | null> {
36
+ const key = offeringSymbol(listing.symbol, listing.exchange);
37
+ if (!key || !periodEnd) return null;
38
+ const { payload } = await loadCloudResource(offeringFilingsCache, key, () => fetchOfferingFilings(client, key, signal), { signal });
39
+ return offeringNote(offeringsAfter(payload, periodEnd), periodEnd);
40
+ }
41
+
42
+ /**
43
+ * The same note for a pane: read only while `enabled` (the views that show
44
+ * cash), from the cached list first. Nothing while it loads or when the read
45
+ * fails, as the note is context, not the data.
46
+ */
47
+ export function useOfferingNote(symbol: string | null | undefined, exchange: string | undefined, periodEnd: string | null, enabled: boolean): string | null {
48
+ const key = enabled && periodEnd ? offeringSymbol(symbol, exchange) : null;
49
+ const loader = useCallback(async (force: boolean) => (
50
+ await loadCloudResource(offeringFilingsCache, key!, () => fetchOfferingFilings(apiClient, key!), { force })
51
+ ).payload, [key]);
52
+ const cached = useMemo(() => key ? cachedCloudResource(offeringFilingsCache, key)?.payload ?? null : null, [key]);
53
+ const { data } = useAsyncResource(key ? loader : null, { initialData: () => cached });
54
+ const filings = data ?? cached;
55
+ return key && periodEnd && filings ? offeringNote(offeringsAfter(filings, periodEnd), periodEnd) : null;
56
+ }
@@ -1,9 +1,10 @@
1
1
  import { createValuationCurrencyContext } from "../../../../time-series/valuation-currency";
2
- import type { FinancialStatement, PricePoint, TickerFinancials } from "../../../../types/financials";
2
+ import type { CompanyProfile, FinancialStatement, PricePoint, TickerFinancials } from "../../../../types/financials";
3
3
  import { formatNumber, pickUnit } from "../../../../utils/format";
4
4
  import { pricePointIntegrity } from "../../../../utils/price-history-integrity";
5
5
  import { formatPerShareNumber } from "../../../../utils/reported-money";
6
6
  import { hasStatementGap } from "../../../../utils/statement-gaps";
7
+ import { cashAndShortTermInvestments, excludesCashRunway, formatRunwayMonths, SHORT_RUNWAY_HISTORY, monthlyOperatingBurn, QUARTER_MONTHS, reportsShortTermTotal, runwayMonths, YEAR_MONTHS } from "../../../../utils/cash-runway";
7
8
  import {
8
9
  buildPreviousStatementMap,
9
10
  trailingFourQuarters,
@@ -21,21 +22,23 @@ import {
21
22
  * Why a ratio or one of its inputs has no number: a line the statements do
22
23
  * not carry for the period, a ratio whose denominator makes it meaningless
23
24
  * (a loss under P/E, negative equity under ROE), no close at the period end,
24
- * a close still loading, or a quarter with fewer than four quarters to sum
25
- * for a trailing flow.
25
+ * a close still loading, a quarter with fewer than four quarters to sum
26
+ * for a trailing flow, or operations that brought cash in, where a runway
27
+ * has no burn to divide by.
26
28
  */
27
- export type RatioGap = "not-reported" | "short-history" | "not-meaningful" | "no-price" | "loading";
29
+ export type RatioGap = "not-reported" | "short-history" | "no-burn" | "not-meaningful" | "no-price" | "loading";
28
30
  export type RatioAmount = number | RatioGap;
29
31
 
30
32
  export const RATIO_GAP_TEXT: Record<RatioGap, string> = {
31
33
  "not-reported": "not reported",
32
- "short-history": "< 4 quarters",
34
+ "short-history": SHORT_RUNWAY_HISTORY,
35
+ "no-burn": "no burn",
33
36
  "not-meaningful": "N/M",
34
37
  "no-price": "no price",
35
38
  loading: "--",
36
39
  };
37
40
 
38
- export type RatioFormat = "percent" | "multiple" | "days";
41
+ export type RatioFormat = "percent" | "multiple" | "days" | "months";
39
42
  export type RatioInputFormat = "money" | "perShare" | "days";
40
43
 
41
44
  /** One column of a ratio tab: a period's statement and what its ratios also need. */
@@ -53,6 +56,8 @@ export interface RatioPeriod {
53
56
  trailing?: FinancialTableStatement | null;
54
57
  /** The close at the period end in the statement's currency. */
55
58
  price: RatioAmount;
59
+ /** The filer reports cash and short-term investments as a total in some period on file (utils/cash-runway). */
60
+ shortTermTotalOnFile?: boolean;
56
61
  }
57
62
 
58
63
  interface RatioInputDef {
@@ -79,6 +84,8 @@ export interface RatioDef {
79
84
  format: RatioFormat;
80
85
  /** The sign carries meaning (a loss, a negative return), so the value takes the sign colour. */
81
86
  signed?: boolean;
87
+ /** Read over one quarter, so the annual view, whose columns are years, leaves it out. */
88
+ quarterlyOnly?: boolean;
82
89
  inputs: RatioInputDef[];
83
90
  /** From the inputs after annualization. */
84
91
  compute: (values: number[], period: RatioPeriod) => RatioAmount;
@@ -277,6 +284,26 @@ const DPO: RatioDef = {
277
284
  compute: ([balance, daily]) => over(balance!, daily!),
278
285
  };
279
286
 
287
+ /** Cash used by operations per month: a quarter's operating cash flow over 3 months, a year's over 12. */
288
+ const monthlyBurn = (months: number) => ({ statement }: RatioPeriod): RatioAmount => (
289
+ monthlyOperatingBurn(finite(statement.operatingCashFlow), months) ?? "not-reported"
290
+ );
291
+
292
+ /** Cash alone for a filer that reports no total with short-term investments, never for one missing it in a period. */
293
+ const runwayCash = ({ statement, shortTermTotalOnFile }: RatioPeriod): RatioAmount => (
294
+ cashAndShortTermInvestments(statement, shortTermTotalOnFile)?.amount ?? "not-reported"
295
+ );
296
+
297
+ /** Months of cash and short-term investments at a monthly operating burn (utils/cash-runway, as `ticker` reads it). */
298
+ const runway = (id: string, label: string, burn: RatioInputDef, quarterlyOnly = false): RatioDef => ({
299
+ id,
300
+ label,
301
+ format: "months",
302
+ ...(quarterlyOnly ? { quarterlyOnly } : {}),
303
+ inputs: [{ label: "Cash + ST Inv", format: "money", value: runwayCash }, burn],
304
+ compute: ([cash, perMonth]) => runwayMonths(cash!, perMonth!),
305
+ });
306
+
280
307
  const dayCount = (label: string, def: RatioDef, operator?: RatioInputDef["operator"]): RatioInputDef => ({
281
308
  label, operator, format: "days", value: (period) => evaluateRatio(def, period).value,
282
309
  });
@@ -440,6 +467,11 @@ export const RATIO_TABS: RatioTabDef[] = [
440
467
  ],
441
468
  compute: ([cash, liabilities]) => over(cash!, liabilities!),
442
469
  },
470
+ // Both burns, as a quarter swings for a company paid in lumps; the trailing one reads the year in annual columns.
471
+ runway("runway-quarter", "Runway, Qtr Burn (mo)",
472
+ { label: "Op Burn/Mo", operator: "÷", format: "money", value: monthlyBurn(QUARTER_MONTHS) }, true),
473
+ runway("runway-ttm", "Runway, TTM Burn (mo)",
474
+ { label: "Op Burn/Mo", operator: "÷", format: "money", trailing: true, value: monthlyBurn(YEAR_MONTHS) }),
443
475
  ],
444
476
  },
445
477
  {
@@ -527,7 +559,7 @@ export const RATIO_TAB_KEYS = new Set(RATIO_TABS.map((tab) => tab.key));
527
559
  * report explains more than a missing close, and a close still loading may
528
560
  * yet arrive.
529
561
  */
530
- const GAP_ORDER: RatioGap[] = ["not-reported", "short-history", "not-meaningful", "no-price", "loading"];
562
+ const GAP_ORDER: RatioGap[] = ["not-reported", "short-history", "no-burn", "not-meaningful", "no-price", "loading"];
531
563
 
532
564
  function inputAmount(input: RatioInputDef, period: RatioPeriod): RatioAmount {
533
565
  if (!input.trailing || !period.quarterly) return input.value(period);
@@ -556,6 +588,7 @@ function ratioInputLabel(input: RatioInputDef, quarterly: boolean): string {
556
588
  export function formatRatioValue(format: RatioFormat, amount: RatioAmount): string {
557
589
  if (isGap(amount)) return RATIO_GAP_TEXT[amount];
558
590
  if (format === "percent") return `${formatNumber(amount * 100, 1)}%`;
591
+ if (format === "months") return formatRunwayMonths(amount, "");
559
592
  if (format === "days") return formatNumber(amount, 1);
560
593
  return `${formatNumber(amount, Math.abs(amount) < 10 ? 2 : 1)}x`;
561
594
  }
@@ -657,7 +690,7 @@ function trailingYear(
657
690
  Math.abs(Date.parse(candidate.date) - end) <= SAME_PERIOD_END_DAYS * 86_400_000
658
691
  && (!candidate.currency || !statement.currency || candidate.currency === statement.currency)
659
692
  ));
660
- return year ?? trailingFourQuarters(quarterlyStatements, statement.date);
693
+ return year ?? trailingFourQuarters(quarterlyStatements, statement.date, annualStatements);
661
694
  }
662
695
 
663
696
  export function ratioPeriods(
@@ -668,6 +701,7 @@ export function ratioPeriods(
668
701
  /** Every statement on file, not only the columns shown, for quarterly columns' trailing years. */
669
702
  onFile: { annual: readonly FinancialStatement[]; quarterly: readonly FinancialStatement[] } = { annual: [], quarterly: [] },
670
703
  ): RatioPeriod[] {
704
+ const shortTermTotalOnFile = reportsShortTermTotal([...onFile.annual, ...onFile.quarterly, ...statements]);
671
705
  return statements.map((statement) => {
672
706
  const quarterly = period === "quarterly" && statement.date !== "TTM";
673
707
  return {
@@ -676,6 +710,7 @@ export function ratioPeriods(
676
710
  quarterly,
677
711
  ...(quarterly ? { trailing: trailingYear(statement, onFile.annual, onFile.quarterly) } : {}),
678
712
  price: price(statement),
713
+ shortTermTotalOnFile,
679
714
  };
680
715
  });
681
716
  }
@@ -700,6 +735,8 @@ export type RatioTableRow =
700
735
 
701
736
  export interface RatioTableModel {
702
737
  tab: RatioTabDef;
738
+ /** The tab's ratios the period shows: a quarterly-only one is left out of years. */
739
+ ratios: RatioDef[];
703
740
  periods: RatioPeriod[];
704
741
  /** Each ratio's cell per period, by ratio id. */
705
742
  cells: Map<string, RatioCell[]>;
@@ -708,14 +745,26 @@ export interface RatioTableModel {
708
745
 
709
746
  const UNIT_WORDS: Record<string, string> = { K: "k", M: "mn", B: "bn", T: "tn" };
710
747
 
748
+ /** The ratios a tab shows for quarterly or annual columns. */
749
+ export function visibleRatios(tab: RatioTabDef, quarterly: boolean): RatioDef[] {
750
+ return quarterly ? tab.ratios : tab.ratios.filter((def) => !def.quarterlyOnly);
751
+ }
752
+
711
753
  export function buildRatioTableModel(
712
754
  tab: RatioTabDef,
713
755
  periods: RatioPeriod[],
714
756
  expandedRatioIds: ReadonlySet<string> | "all",
757
+ profile?: CompanyProfile,
715
758
  ): RatioTableModel {
716
759
  const quarterly = periods.some((period) => period.quarterly);
717
- const cells = new Map(tab.ratios.map((def) => [def.id, periods.map((period) => evaluateRatio(def, period))]));
718
- const inputs = tab.ratios.flatMap((def) => def.inputs.map((input, index) => {
760
+ const totalOnFile = periods.some((period) => period.shortTermTotalOnFile);
761
+ const ratios = visibleRatios(tab, quarterly)
762
+ .filter((def) => def.format !== "months" || !excludesCashRunway(profile))
763
+ .map((def) => def.format === "months" && !totalOnFile
764
+ ? { ...def, inputs: def.inputs.map((input, index) => index === 0 ? { ...input, label: "Cash" } : input) }
765
+ : def);
766
+ const cells = new Map(ratios.map((def) => [def.id, periods.map((period) => evaluateRatio(def, period))]));
767
+ const inputs = ratios.flatMap((def) => def.inputs.map((input, index) => {
719
768
  const values = cells.get(def.id)!.map((cell) => cell.inputs[index]).filter((value) => typeof value === "number");
720
769
  const { suffix, divisor } = input.format === "money" ? pickUnit(values) : { suffix: "", divisor: 1 };
721
770
  const unit = UNIT_WORDS[suffix] ?? suffix;
@@ -733,12 +782,12 @@ export function buildRatioTableModel(
733
782
  // Each money input names its unit: a ratio tab has few of them, and a unit
734
783
  // stated once in the query bar is the first thing a narrow pane cuts.
735
784
  const rows: RatioTableRow[] = [];
736
- for (const def of tab.ratios) {
785
+ for (const def of ratios) {
737
786
  const expanded = expandedRatioIds === "all" || expandedRatioIds.has(def.id);
738
787
  rows.push({ kind: "ratio", id: def.id, def, label: def.label, expanded });
739
788
  if (expanded) rows.push(...inputs.filter((row) => row.def === def));
740
789
  }
741
- return { tab, periods, cells, rows };
790
+ return { tab, ratios, periods, cells, rows };
742
791
  }
743
792
 
744
793
  export const findRatioTab = (key: string) => RATIO_TABS.find((tab) => tab.key === key);
@@ -777,5 +826,5 @@ export function ratioTableForFinancials(
777
826
  const close = history ? periodEndClose(history, ratioPeriodEnd(statement)) : undefined;
778
827
  return (close === undefined ? null : currencies.priceInStatementUnits(statement, close)) ?? "no-price";
779
828
  };
780
- return buildRatioTableModel(tab, ratioPeriods(statements, ratioOpenings(period, annual, quarterly), period, price, { annual, quarterly }), "all");
829
+ return buildRatioTableModel(tab, ratioPeriods(statements, ratioOpenings(period, annual, quarterly), period, price, { annual, quarterly }), "all", financials.profile);
781
830
  }