gloomberb 0.18.3 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (886) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/src/account/checkout-handoff.tsx +225 -0
  6. package/src/account/device-signin-dialog.tsx +2 -2
  7. package/src/account/device-signin.ts +2 -2
  8. package/src/account/upgrade-dialog.tsx +1 -1
  9. package/src/api-client/askg.ts +2 -2
  10. package/src/api-client/auth.ts +2 -2
  11. package/src/api-client/central-bank-rates.ts +6 -0
  12. package/src/api-client/collections.ts +5 -1
  13. package/src/api-client/cot.ts +2 -0
  14. package/src/api-client/crypto-etf-flows.ts +37 -0
  15. package/src/api-client/crypto-markets.ts +60 -0
  16. package/src/api-client/data.ts +84 -5
  17. package/src/api-client/doe.ts +15 -0
  18. package/src/api-client/equity-screener.ts +28 -0
  19. package/src/api-client/exchange-announcements.ts +38 -0
  20. package/src/api-client/fund-facts.ts +39 -0
  21. package/src/api-client/futures-curve.ts +9 -1
  22. package/src/api-client/hiring.ts +301 -0
  23. package/src/api-client/index.ts +22 -5
  24. package/src/api-client/market-discovery.ts +14 -0
  25. package/src/api-client/members.ts +6 -0
  26. package/src/api-client/mna.ts +6 -0
  27. package/src/api-client/paths.ts +18 -1
  28. package/src/api-client/request.ts +21 -4
  29. package/src/api-client/short-side-publications.ts +37 -0
  30. package/src/api-client/socket.ts +64 -4
  31. package/src/api-client/swap-curve.ts +35 -0
  32. package/src/api-client/themes.ts +7 -1
  33. package/src/api-client/types.ts +90 -2
  34. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  35. package/src/app/runtime/desktop-deeplink.ts +5 -5
  36. package/src/app/runtime/plugin-bindings.ts +2 -2
  37. package/src/app/runtime/startup.ts +13 -0
  38. package/src/app/star-prompt/status-line.tsx +2 -2
  39. package/src/architecture/core-builtin-allowlist.json +5 -2
  40. package/src/architecture/ui-literals-allowlist.json +3 -3
  41. package/src/architecture/ui-tokens-allowlist.json +1 -1
  42. package/src/brokers/broker-portfolio-sync.ts +37 -0
  43. package/src/brokers/directory.ts +11 -0
  44. package/src/brokers/logos.ts +3 -1
  45. package/src/brokers/signed-in/adapter.ts +304 -26
  46. package/src/brokers/signed-in/client.ts +14 -2
  47. package/src/brokers/signed-in/connect.ts +10 -2
  48. package/src/brokers/sync-broker-instance.ts +9 -1
  49. package/src/capabilities/chart-series.ts +22 -6
  50. package/src/cli/bank-section.ts +1 -1
  51. package/src/cli/base-converter.ts +23 -14
  52. package/src/cli/central-bank-events.ts +1 -1
  53. package/src/cli/command-options.ts +59 -4
  54. package/src/cli/commands/api.ts +9 -6
  55. package/src/cli/commands/broker.ts +2 -2
  56. package/src/cli/commands/command-utils.ts +2 -2
  57. package/src/cli/commands/crypto-hints.ts +7 -20
  58. package/src/cli/commands/fred-series.ts +4 -2
  59. package/src/cli/commands/keybindings.ts +2 -2
  60. package/src/cli/commands/market.ts +1117 -264
  61. package/src/cli/commands/news-hints.ts +2 -2
  62. package/src/cli/commands/news-search.ts +59 -6
  63. package/src/cli/commands/options-leaps.ts +41 -26
  64. package/src/cli/commands/overview.ts +121 -48
  65. package/src/cli/commands/plugins.ts +9 -9
  66. package/src/cli/commands/remote.ts +13 -10
  67. package/src/cli/commands/search.ts +64 -44
  68. package/src/cli/commands/system.ts +27 -19
  69. package/src/cli/commands/themes.ts +1 -1
  70. package/src/cli/commands/ticker.ts +192 -47
  71. package/src/cli/context.ts +3 -2
  72. package/src/cli/desktop-pane-shot-view.ts +2 -2
  73. package/src/cli/desktop-pane-shot.ts +1 -1
  74. package/src/cli/earnings-calendar.ts +4 -4
  75. package/src/cli/entry.ts +18 -1
  76. package/src/cli/errors.ts +20 -2
  77. package/src/cli/exit-codes.ts +1 -1
  78. package/src/cli/export-source.ts +10 -4
  79. package/src/cli/freshness.ts +2 -8
  80. package/src/cli/fx-forward.ts +130 -0
  81. package/src/cli/fx-pair.ts +10 -9
  82. package/src/cli/glossary.ts +64 -20
  83. package/src/cli/help.ts +19 -13
  84. package/src/cli/history-export.ts +126 -0
  85. package/src/cli/history-rows.ts +196 -43
  86. package/src/cli/index-roots.ts +5 -45
  87. package/src/cli/index.ts +24 -18
  88. package/src/cli/known-gaps.ts +118 -25
  89. package/src/cli/listing-arg.ts +300 -41
  90. package/src/cli/name-entries.ts +30 -18
  91. package/src/cli/native-smoke.ts +2 -0
  92. package/src/cli/not-a-ticker.ts +19 -9
  93. package/src/cli/opentui-libc.ts +5 -0
  94. package/src/cli/options.ts +12 -0
  95. package/src/cli/pane-functions/capabilities.ts +75 -20
  96. package/src/cli/pane-functions/catalog.ts +24 -23
  97. package/src/cli/pane-functions/discovery.ts +1 -1
  98. package/src/cli/pane-functions/dom.ts +10 -7
  99. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  100. package/src/cli/pane-functions/freshness.ts +174 -23
  101. package/src/cli/pane-functions/function-help.ts +66 -27
  102. package/src/cli/pane-functions/headless.ts +24 -11
  103. package/src/cli/pane-functions/index.ts +18 -16
  104. package/src/cli/pane-functions/options.ts +22 -2
  105. package/src/cli/pane-functions/report-notices.ts +12 -4
  106. package/src/cli/pane-functions/report.ts +5 -5
  107. package/src/cli/pane-functions/resolver.ts +47 -10
  108. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  109. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  110. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  111. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  112. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  113. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  114. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  115. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  116. package/src/cli/pane-functions/shot-options.ts +8 -3
  117. package/src/cli/peso-dollar-rates.ts +79 -0
  118. package/src/cli/quote-answer.ts +38 -3
  119. package/src/cli/report-tables.ts +61 -16
  120. package/src/cli/restore-plugins.ts +29 -14
  121. package/src/cli/result.ts +111 -22
  122. package/src/cli/series-search.ts +5 -5
  123. package/src/cli/statement-filings.ts +19 -0
  124. package/src/cli/suffixed-listing-rows.ts +49 -0
  125. package/src/cli/symbol-args.ts +50 -15
  126. package/src/cli/symbol-cells.ts +120 -0
  127. package/src/cli/symbol-list.ts +198 -68
  128. package/src/cli/symbol-rows.ts +131 -25
  129. package/src/cli/ticker-resolution.ts +108 -11
  130. package/src/cli/treasury-yields.ts +5 -5
  131. package/src/cli/types.ts +2 -0
  132. package/src/cli/uncovered-instrument.ts +3 -3
  133. package/src/cli/unknown-command.ts +6 -6
  134. package/src/components/chart/composite/chart-layout.ts +131 -0
  135. package/src/components/chart/composite/composite-chart.tsx +373 -16
  136. package/src/components/chart/composite/interactions.ts +7 -2
  137. package/src/components/chart/composite/legend.tsx +75 -3
  138. package/src/components/chart/composite/levels.ts +5 -0
  139. package/src/components/chart/composite/panel-gestures.ts +41 -0
  140. package/src/components/chart/composite/panel-labels.ts +2 -1
  141. package/src/components/chart/composite/panel-surface.tsx +305 -11
  142. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  143. package/src/components/chart/composite/rasterizer.ts +44 -19
  144. package/src/components/chart/composite/scene.ts +16 -4
  145. package/src/components/chart/composite/text-renderer.ts +48 -21
  146. package/src/components/chart/composite/toolbar.tsx +52 -5
  147. package/src/components/chart/composite/types.ts +13 -0
  148. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  149. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  150. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  151. package/src/components/chart/composite/value-scale.ts +149 -0
  152. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  153. package/src/components/chart/core/pointer.ts +2 -0
  154. package/src/components/chart-table/index.ts +2 -0
  155. package/src/components/chart-table/read.tsx +74 -0
  156. package/src/components/command-bar/commands/collection-list.ts +41 -19
  157. package/src/components/command-bar/commands/collection.ts +9 -3
  158. package/src/components/command-bar/commands/direct/index.ts +1 -1
  159. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  160. package/src/components/command-bar/pane-templates/items.ts +59 -6
  161. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  162. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  163. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  164. package/src/components/command-bar/routes/root/results.ts +18 -4
  165. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  166. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  167. package/src/components/command-bar/routes/root/selection.ts +6 -1
  168. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  169. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  170. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  171. package/src/components/command-bar/selection-runtime.ts +50 -10
  172. package/src/components/command-bar/surface/index.tsx +24 -2
  173. package/src/components/command-bar/view-model.ts +7 -0
  174. package/src/components/command-bar/workflow/broker.ts +2 -2
  175. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  176. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  177. package/src/components/command-bar/workflow/fields.ts +8 -2
  178. package/src/components/command-bar/workflow/ops.ts +18 -4
  179. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  180. package/src/components/command-bar/workflow/submit.ts +3 -2
  181. package/src/components/command-bar/workflow/tickers.ts +5 -1
  182. package/src/components/company-logo.tsx +39 -0
  183. package/src/components/data-table/sections.ts +4 -2
  184. package/src/components/form-modal/confirm.tsx +2 -1
  185. package/src/components/form-modal/request.ts +5 -0
  186. package/src/components/form-modal/routes.ts +4 -1
  187. package/src/components/index.ts +12 -6
  188. package/src/components/layout/header.tsx +7 -6
  189. package/src/components/layout/market-summary.ts +9 -6
  190. package/src/components/layout/pane/capture-status.ts +1 -1
  191. package/src/components/layout/pane/footer/model.ts +11 -5
  192. package/src/components/layout/shell/chrome.ts +19 -6
  193. package/src/components/layout/shell/index.tsx +2 -1
  194. package/src/components/layout/shell/pane/layers.tsx +19 -1
  195. package/src/components/layout/status-bar.tsx +2 -2
  196. package/src/components/market-board/index.tsx +11 -3
  197. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  198. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  199. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  200. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  201. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  202. package/src/components/pane-settings-dialog/value.ts +8 -1
  203. package/src/components/pane-settings-dialog.tsx +44 -13
  204. package/src/components/sign-in-code-panel.tsx +27 -19
  205. package/src/components/ui/column-grid.tsx +48 -4
  206. package/src/components/ui/country-flag-art.tsx +180 -0
  207. package/src/components/ui/country-flag.tsx +118 -12
  208. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  209. package/src/components/ui/data-table/opentui/model.ts +109 -2
  210. package/src/components/ui/data-table/types.ts +1 -1
  211. package/src/components/ui/display.tsx +5 -1
  212. package/src/components/ui/index.ts +3 -1
  213. package/src/components/ui/logo-mark.tsx +11 -2
  214. package/src/components/ui/query-bar.tsx +1 -1
  215. package/src/components/ui/row-notes.ts +79 -0
  216. package/src/core/state/app/layout.ts +4 -4
  217. package/src/data/cached-query.ts +8 -1
  218. package/src/data/config/chart-settings.ts +3 -3
  219. package/src/data/config/home.ts +10 -2
  220. package/src/data/config/layout.ts +4 -1
  221. package/src/data/config/store/node.ts +4 -0
  222. package/src/data/config/store/normalize.ts +13 -3
  223. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  224. package/src/data/json-storage.ts +2 -0
  225. package/src/data/saved-copies.ts +84 -0
  226. package/src/docs/snapshot.json +65 -32
  227. package/src/i18n/es.ts +29 -12
  228. package/src/i18n/ja.ts +29 -12
  229. package/src/i18n/ko.ts +29 -12
  230. package/src/i18n/zh-cn.ts +29 -12
  231. package/src/i18n/zh-tw.ts +29 -12
  232. package/src/layout/desks.ts +1 -1
  233. package/src/layout/launch-layout.ts +1 -1
  234. package/src/layout/pane-manager/floating-actions.ts +5 -3
  235. package/src/layout/pane-manager/floating.ts +43 -1
  236. package/src/layout/pane-manager/index.ts +2 -0
  237. package/src/layout/selected-ticker.ts +74 -0
  238. package/src/market-data/depositary-pair.ts +251 -0
  239. package/src/market-data/futures-board.ts +1 -1
  240. package/src/market-data/futures-contract.ts +124 -40
  241. package/src/market-data/fx-closes.ts +17 -2
  242. package/src/market-data/hooks.tsx +19 -11
  243. package/src/market-data/market/change-basis.ts +49 -7
  244. package/src/market-data/market/freshness.ts +34 -5
  245. package/src/market-data/market/period-return.ts +163 -0
  246. package/src/market-data/market/trading-sessions.ts +13 -0
  247. package/src/market-data/market/year-to-date.ts +8 -13
  248. package/src/market-data/performance.ts +20 -14
  249. package/src/market-data/perpetual-premium.ts +32 -0
  250. package/src/market-data/published-apac-sessions.ts +2 -1
  251. package/src/market-data/published-futures-sessions.ts +69 -0
  252. package/src/market-data/quotes/contributions.ts +5 -1
  253. package/src/market-data/quotes/freshness.ts +42 -0
  254. package/src/market-data/quotes/intraday-bar.ts +37 -0
  255. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  256. package/src/market-data/quotes/resolution.ts +4 -2
  257. package/src/market-data/tax-equivalent.ts +1 -1
  258. package/src/market-data/ticker-price-returns.ts +3 -1
  259. package/src/news/aggregator.ts +5 -1
  260. package/src/news/news-model.ts +4 -0
  261. package/src/news/types.ts +11 -0
  262. package/src/notifications/app-notifier.ts +1 -1
  263. package/src/plugins/auto-update.ts +2 -2
  264. package/src/plugins/builtin/account-management/index.tsx +1 -0
  265. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  266. package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
  267. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  268. package/src/plugins/builtin/alerts/cli.ts +485 -76
  269. package/src/plugins/builtin/alerts/command.ts +5 -10
  270. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  271. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  272. package/src/plugins/builtin/alerts/events.ts +107 -5
  273. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  274. package/src/plugins/builtin/alerts/format.ts +2 -1
  275. package/src/plugins/builtin/alerts/headless.ts +100 -39
  276. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  277. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  278. package/src/plugins/builtin/alerts/index.tsx +45 -18
  279. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  280. package/src/plugins/builtin/alerts/levels.ts +3 -3
  281. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  282. package/src/plugins/builtin/alerts/price.ts +35 -0
  283. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  284. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  285. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  286. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  287. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  288. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  289. package/src/plugins/builtin/alerts/storage.ts +13 -10
  290. package/src/plugins/builtin/alerts/targets.ts +12 -3
  291. package/src/plugins/builtin/analytics/index.tsx +8 -2
  292. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  293. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  294. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  295. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  296. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  297. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  298. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  299. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  300. package/src/plugins/builtin/attention/pane.tsx +6 -2
  301. package/src/plugins/builtin/awards/headless.ts +7 -3
  302. package/src/plugins/builtin/awards/model.ts +18 -0
  303. package/src/plugins/builtin/awards/pane.tsx +6 -3
  304. package/src/plugins/builtin/backtest/headless.ts +3 -3
  305. package/src/plugins/builtin/backtest/rules.ts +41 -5
  306. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  307. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  308. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  309. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  310. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  311. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  312. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  313. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  314. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  315. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  316. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  317. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  318. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  319. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  320. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  321. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  322. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  323. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  324. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  325. package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
  326. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  327. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  328. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  329. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  330. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  331. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  332. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  333. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  334. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  335. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  336. package/src/plugins/builtin/catalysts/model.ts +49 -4
  337. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  338. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  339. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  340. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  341. package/src/plugins/builtin/changelog/index.tsx +1 -0
  342. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  343. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  344. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  345. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  346. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  347. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  348. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  349. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  350. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  351. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  352. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  353. package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
  354. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  355. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  356. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  357. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  358. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  359. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  360. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  361. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  362. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  363. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  364. package/src/plugins/builtin/chat/people.ts +1 -1
  365. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  366. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  367. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  368. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  369. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  370. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  371. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  372. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  373. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  374. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  375. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  376. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  377. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  378. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  379. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  380. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  381. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  382. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  383. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  384. package/src/plugins/builtin/company-attention/client.ts +117 -1
  385. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  386. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  387. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  388. package/src/plugins/builtin/company-attention/model.ts +33 -7
  389. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  390. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  391. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  392. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  393. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  394. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  395. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  396. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  397. package/src/plugins/builtin/composite-plugins.ts +2 -1
  398. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  399. package/src/plugins/builtin/connections/index.ts +1 -0
  400. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  401. package/src/plugins/builtin/correlation/headless.ts +5 -3
  402. package/src/plugins/builtin/cot/headless.ts +28 -6
  403. package/src/plugins/builtin/cot/model.ts +12 -0
  404. package/src/plugins/builtin/cot/pane.tsx +3 -2
  405. package/src/plugins/builtin/cpi/headless.ts +5 -1
  406. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  407. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  408. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  409. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  410. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  411. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  412. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  413. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  414. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  415. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  416. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  417. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  418. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  419. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  420. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  421. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  422. package/src/plugins/builtin/debug/index.tsx +1 -0
  423. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  424. package/src/plugins/builtin/docs/index.tsx +1 -1
  425. package/src/plugins/builtin/docs/pane.tsx +2 -2
  426. package/src/plugins/builtin/docs/targets.ts +1 -1
  427. package/src/plugins/builtin/doe/client.ts +5 -1
  428. package/src/plugins/builtin/doe/headless.ts +12 -6
  429. package/src/plugins/builtin/doe/model.ts +43 -6
  430. package/src/plugins/builtin/doe/pane.tsx +18 -11
  431. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  432. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  433. package/src/plugins/builtin/earnings/board.tsx +253 -50
  434. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  435. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  436. package/src/plugins/builtin/earnings/client.ts +4 -3
  437. package/src/plugins/builtin/earnings/headless.ts +53 -15
  438. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  439. package/src/plugins/builtin/earnings/index.tsx +15 -22
  440. package/src/plugins/builtin/earnings/model.ts +17 -12
  441. package/src/plugins/builtin/earnings/scope.ts +89 -0
  442. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  443. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  444. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  445. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  446. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  447. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  448. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  449. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  450. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  451. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  452. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  453. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  454. package/src/plugins/builtin/econ/index.tsx +112 -25
  455. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  456. package/src/plugins/builtin/econ/types.ts +32 -1
  457. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  458. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  459. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  460. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  461. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  462. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  463. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  464. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  465. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  466. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  467. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  468. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  469. package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
  470. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  471. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  472. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  473. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  474. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  475. package/src/plugins/builtin/exposure/headless.ts +51 -6
  476. package/src/plugins/builtin/exposure/index.tsx +28 -2
  477. package/src/plugins/builtin/exposure/model.ts +7 -0
  478. package/src/plugins/builtin/exposure/pane.tsx +6 -1
  479. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  480. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  481. package/src/plugins/builtin/futures/model.ts +10 -9
  482. package/src/plugins/builtin/futures/returns.ts +8 -36
  483. package/src/plugins/builtin/futures/table.tsx +1 -1
  484. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  485. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  486. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  487. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  488. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  489. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  490. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  491. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  492. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  493. package/src/plugins/builtin/gpu/headless.ts +9 -4
  494. package/src/plugins/builtin/help/index.tsx +13 -3
  495. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  496. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  497. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  498. package/src/plugins/builtin/holders/client.ts +13 -1
  499. package/src/plugins/builtin/holders/format.ts +28 -17
  500. package/src/plugins/builtin/holders/headless.ts +46 -7
  501. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  502. package/src/plugins/builtin/holders/pane.tsx +79 -15
  503. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  504. package/src/plugins/builtin/holders/table-model.ts +2 -1
  505. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  506. package/src/plugins/builtin/insider/headless.ts +1 -1
  507. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  508. package/src/plugins/builtin/insider/signals.tsx +1 -1
  509. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  510. package/src/plugins/builtin/iv-history/client.ts +20 -0
  511. package/src/plugins/builtin/iv-history/headless.ts +4 -4
  512. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  513. package/src/plugins/builtin/iv-history/model.ts +13 -4
  514. package/src/plugins/builtin/iv-history/series.ts +3 -1
  515. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  516. package/src/plugins/builtin/jobs/model.ts +4 -15
  517. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  518. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  519. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  520. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  521. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  522. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  523. package/src/plugins/builtin/macro-day/model.ts +29 -8
  524. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  525. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  526. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  527. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  528. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  529. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  530. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  531. package/src/plugins/builtin/market-movers/client.ts +33 -19
  532. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  533. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  534. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  535. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  536. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  537. package/src/plugins/builtin/market-movers/table.ts +4 -1
  538. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  539. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  540. package/src/plugins/builtin/members/headless.ts +6 -5
  541. package/src/plugins/builtin/members/pane.tsx +11 -4
  542. package/src/plugins/builtin/mna/client.ts +1 -0
  543. package/src/plugins/builtin/mna/detail.tsx +20 -32
  544. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  545. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  546. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  547. package/src/plugins/builtin/mna/headless.ts +6 -13
  548. package/src/plugins/builtin/mna/model.ts +93 -15
  549. package/src/plugins/builtin/mna/pane.tsx +5 -4
  550. package/src/plugins/builtin/news/headless.ts +12 -6
  551. package/src/plugins/builtin/news/index.tsx +10 -1
  552. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  553. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  554. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  555. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  556. package/src/plugins/builtin/notes/cli.ts +49 -14
  557. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  558. package/src/plugins/builtin/options/carry.ts +2 -2
  559. package/src/plugins/builtin/options/index.tsx +1 -1
  560. package/src/plugins/builtin/options/view.tsx +10 -10
  561. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  562. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  563. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  564. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  565. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  566. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  567. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  568. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  569. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  570. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  571. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  572. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  573. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  574. package/src/plugins/builtin/perps/freshness.ts +8 -5
  575. package/src/plugins/builtin/perps/headless.ts +3 -1
  576. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  577. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  578. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  579. package/src/plugins/builtin/perps/pane.tsx +36 -17
  580. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  581. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  582. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  583. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  584. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  585. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  586. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  587. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  588. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  589. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  590. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  591. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  592. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  593. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  594. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  595. package/src/plugins/builtin/power/client.ts +4 -1
  596. package/src/plugins/builtin/power/evidence.ts +22 -7
  597. package/src/plugins/builtin/power/gas.tsx +5 -1
  598. package/src/plugins/builtin/power/pane.tsx +8 -1
  599. package/src/plugins/builtin/power/prices.tsx +10 -3
  600. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  601. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  602. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  603. package/src/plugins/builtin/research/event-model.ts +3 -1
  604. package/src/plugins/builtin/research/event-sources.ts +12 -4
  605. package/src/plugins/builtin/research/index.tsx +2 -1
  606. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  607. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  608. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  609. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  610. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  611. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  612. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  613. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  614. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  615. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  616. package/src/plugins/builtin/sec/forms.ts +13 -0
  617. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  618. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  619. package/src/plugins/builtin/sec/headless.ts +85 -8
  620. package/src/plugins/builtin/sec/index.tsx +58 -12
  621. package/src/plugins/builtin/sectors/client.ts +2 -1
  622. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  623. package/src/plugins/builtin/series-inventory.ts +2 -0
  624. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  625. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  626. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  627. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  628. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  629. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  630. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  631. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  632. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  633. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  634. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  635. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  636. package/src/plugins/builtin/short-interest/client.ts +2 -0
  637. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  638. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  639. package/src/plugins/builtin/short-interest/model.ts +70 -19
  640. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  641. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  642. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  643. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  644. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  645. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  646. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  647. package/src/plugins/builtin/short-interest/types.ts +9 -0
  648. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  649. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  650. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  651. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  652. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  653. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  654. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  655. package/src/plugins/builtin/themes/headless.ts +8 -5
  656. package/src/plugins/builtin/themes/model.ts +14 -4
  657. package/src/plugins/builtin/themes/pane.tsx +24 -5
  658. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  659. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  660. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  661. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  662. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  663. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  664. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  665. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  666. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  667. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  668. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  669. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  670. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  671. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  672. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  673. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  674. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  675. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  676. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  677. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  678. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  679. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  680. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  681. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  682. package/src/plugins/builtin/vol-surface/client.ts +5 -4
  683. package/src/plugins/builtin/vol-surface/headless.ts +12 -3
  684. package/src/plugins/builtin/vol-surface/model.ts +4 -2
  685. package/src/plugins/builtin/volatility/model.ts +5 -10
  686. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  687. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  688. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  689. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  690. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  691. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  692. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  693. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  694. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  695. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  696. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  697. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  698. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  699. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  700. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  701. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  702. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  703. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  704. package/src/plugins/bundle.ts +1 -1
  705. package/src/plugins/catalog-browser.ts +2 -1
  706. package/src/plugins/compat.ts +3 -3
  707. package/src/plugins/dependencies.ts +75 -14
  708. package/src/plugins/extracted-plugins.ts +132 -34
  709. package/src/plugins/host-link.ts +149 -34
  710. package/src/plugins/installer.ts +35 -10
  711. package/src/plugins/loader.ts +206 -38
  712. package/src/plugins/manager-node.ts +2 -2
  713. package/src/plugins/marketplace/deactivation.ts +22 -0
  714. package/src/plugins/marketplace/model.ts +2 -2
  715. package/src/plugins/marketplace/packs.ts +1 -1
  716. package/src/plugins/ownership.ts +1 -1
  717. package/src/plugins/peer-retry.ts +155 -0
  718. package/src/plugins/registry/contributions.ts +3 -1
  719. package/src/plugins/registry/index.ts +4 -3
  720. package/src/plugins/registry/plugin-state.ts +3 -0
  721. package/src/plugins/seed-notice.ts +20 -0
  722. package/src/plugins/shortcut-argument.ts +39 -0
  723. package/src/portfolio/allocation.ts +1 -1
  724. package/src/portfolio/collection-name.ts +31 -0
  725. package/src/portfolio/column-values.ts +10 -8
  726. package/src/portfolio/cost-fx.ts +296 -19
  727. package/src/portfolio/manual-lots.ts +75 -0
  728. package/src/portfolio/mutations.ts +60 -22
  729. package/src/portfolio/suffixed-listings.ts +209 -0
  730. package/src/portfolio/totals-currency.ts +24 -0
  731. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  732. package/src/public/time-series.ts +11 -8
  733. package/src/remote/schema.ts +1 -1
  734. package/src/renderers/browser/config-host.ts +3 -0
  735. package/src/renderers/browser/main.tsx +23 -3
  736. package/src/renderers/dom/boot-frame-page.ts +187 -0
  737. package/src/renderers/dom/boot-frame.ts +237 -0
  738. package/src/renderers/dom/build-assets.ts +46 -8
  739. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  740. package/src/renderers/dom/host/ascii-text.ts +16 -2
  741. package/src/renderers/dom/host/box.tsx +43 -2
  742. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  743. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  744. package/src/renderers/dom/host/image-surface.tsx +49 -0
  745. package/src/renderers/dom/host/media-surface.tsx +24 -18
  746. package/src/renderers/dom/host/mouse.ts +30 -0
  747. package/src/renderers/dom/host/size-observer.ts +1 -1
  748. package/src/renderers/dom/host/style.ts +1 -1
  749. package/src/renderers/dom/styles.css +76 -0
  750. package/src/renderers/dom/test-utils.tsx +2 -1
  751. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  752. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  753. package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
  754. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  755. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  756. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  757. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  758. package/src/renderers/electrobun/bun/index.ts +11 -1
  759. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  760. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  761. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  762. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  763. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  764. package/src/renderers/electrobun/view/config-host.ts +3 -0
  765. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  766. package/src/renderers/electrobun/view/main.tsx +30 -4
  767. package/src/renderers/electrobun/view/news-source.ts +5 -5
  768. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  769. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  770. package/src/renderers/opentui/browser-open.ts +88 -0
  771. package/src/renderers/opentui/host.tsx +5 -14
  772. package/src/renderers/opentui/image/loader.ts +3 -2
  773. package/src/renderers/opentui/native-smoke.ts +10 -1
  774. package/src/renderers/opentui/pane-image/index.ts +2 -1
  775. package/src/renderers/opentui/render-lib.ts +253 -0
  776. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  777. package/src/renderers/opentui/start.tsx +1 -1
  778. package/src/renderers/share/layout-view.tsx +2 -2
  779. package/src/renderers/share/main.tsx +4 -4
  780. package/src/renderers/share/view.tsx +1 -1
  781. package/src/series/resolve.ts +22 -6
  782. package/src/series/standalone.ts +30 -2
  783. package/src/series/types.ts +8 -1
  784. package/src/shares/api.ts +4 -1
  785. package/src/shares/pane.ts +1 -1
  786. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  787. package/src/sources/gloomberb-cloud/index.ts +32 -16
  788. package/src/sources/gloomberb-cloud/news.ts +39 -0
  789. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  790. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  791. package/src/sources/listing-symbols.ts +37 -0
  792. package/src/sources/provider-errors.ts +16 -2
  793. package/src/sources/provider-router/financial-routes.ts +21 -3
  794. package/src/sources/provider-router/financials.ts +15 -2
  795. package/src/sources/provider-router/history.ts +30 -8
  796. package/src/sources/provider-router/primary.ts +1 -1
  797. package/src/state/app/bootstrap.ts +23 -0
  798. package/src/state/hooks/inline-tickers.ts +30 -5
  799. package/src/sync/controller.ts +1 -1
  800. package/src/sync/core-contributors.ts +46 -14
  801. package/src/team/collections-sync.ts +2 -1
  802. package/src/team/collections.ts +178 -17
  803. package/src/telemetry/crash-reports.ts +17 -4
  804. package/src/test-support/builtin-panes.ts +1 -1
  805. package/src/theme/colors.ts +3 -30
  806. package/src/theme/ui-tokens.ts +37 -1
  807. package/src/tickers/company-name-listing.ts +210 -33
  808. package/src/tickers/index-roots.ts +47 -0
  809. package/src/tickers/instrument-label.ts +5 -1
  810. package/src/tickers/metadata.ts +10 -0
  811. package/src/tickers/perpetual-listing.ts +5 -2
  812. package/src/tickers/search/home-listing.ts +75 -0
  813. package/src/tickers/search/index.ts +76 -27
  814. package/src/tickers/search/ranking.ts +54 -4
  815. package/src/tickers/search/upsert.ts +29 -0
  816. package/src/tickers/terminal-codes.ts +416 -40
  817. package/src/time-series/bar-aggregation.ts +243 -0
  818. package/src/time-series/base-series.ts +307 -0
  819. package/src/time-series/chart-bounds.ts +349 -0
  820. package/src/time-series/chart-seed.ts +142 -0
  821. package/src/time-series/economic.ts +5 -0
  822. package/src/time-series/fundamentals.ts +18 -3
  823. package/src/time-series/history-acquisition.ts +499 -0
  824. package/src/time-series/leverage.ts +100 -0
  825. package/src/time-series/market-resolution.ts +4 -2
  826. package/src/time-series/market.ts +2 -1
  827. package/src/time-series/price-comparison.ts +175 -30
  828. package/src/time-series/range.ts +9 -1
  829. package/src/time-series/resolution.ts +174 -16
  830. package/src/time-series/resolve-context.ts +157 -0
  831. package/src/time-series/resolve.ts +126 -1577
  832. package/src/time-series/series-name.ts +38 -0
  833. package/src/time-series/series-presentation.ts +208 -0
  834. package/src/time-series/spec.ts +11 -6
  835. package/src/time-series/studies.ts +109 -12
  836. package/src/time-series/tail-reconcile.ts +121 -0
  837. package/src/time-series/types.ts +29 -2
  838. package/src/time-series/use-chart-resolution.ts +4 -5
  839. package/src/types/broker.ts +10 -0
  840. package/src/types/config.ts +14 -0
  841. package/src/types/data-provider.ts +14 -0
  842. package/src/types/exchange-rate.ts +6 -0
  843. package/src/types/financials.ts +104 -7
  844. package/src/types/headless.ts +76 -6
  845. package/src/types/instrument.ts +3 -0
  846. package/src/types/plugin.ts +65 -8
  847. package/src/types/price-history.ts +2 -0
  848. package/src/types/ticker.ts +13 -0
  849. package/src/types/trading.ts +59 -1
  850. package/src/ui/ascii-font.ts +13 -1
  851. package/src/ui/host.tsx +6 -1
  852. package/src/updater/command-names.ts +175 -0
  853. package/src/updater/index.ts +10 -5
  854. package/src/utils/calendar-date.ts +32 -15
  855. package/src/utils/cash-runway.ts +241 -0
  856. package/src/utils/central-banks.ts +42 -0
  857. package/src/utils/cli-output.ts +259 -80
  858. package/src/utils/contract-month.ts +16 -0
  859. package/src/utils/crypto-pair.ts +61 -3
  860. package/src/utils/currency-units.ts +29 -0
  861. package/src/utils/datetime-format.ts +10 -0
  862. package/src/utils/debug-log.ts +1 -1
  863. package/src/utils/decimal-comma.ts +39 -6
  864. package/src/utils/exchange-announcements.ts +71 -0
  865. package/src/utils/exchange-rate-snapshot.ts +10 -0
  866. package/src/utils/financial-statements.ts +83 -4
  867. package/src/utils/format.ts +34 -16
  868. package/src/utils/fundamentals.ts +150 -34
  869. package/src/utils/fx-market-hours.ts +10 -1
  870. package/src/utils/latest-financial-period.ts +8 -0
  871. package/src/utils/linux-libc.ts +54 -0
  872. package/src/utils/market-capitalization.ts +111 -15
  873. package/src/utils/max-drawdown.ts +64 -0
  874. package/src/utils/network-failure.ts +83 -0
  875. package/src/utils/option-expiry.ts +139 -7
  876. package/src/utils/price-earnings.ts +11 -5
  877. package/src/utils/price-history.ts +18 -8
  878. package/src/utils/price-window.ts +131 -0
  879. package/src/utils/release-date.ts +47 -0
  880. package/src/utils/sec.ts +3 -0
  881. package/src/utils/throttled-fetch.ts +11 -4
  882. package/src/utils/trailing-eps.ts +67 -0
  883. package/src/utils/typed-text.ts +21 -0
  884. package/src/utils/utc-time.ts +24 -1
  885. package/src/version.ts +6 -0
  886. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -0,0 +1,142 @@
1
+ import { logFailure } from "../../../utils/log-failure";
2
+ import type { ChartSeriesSpec, ChartSpec, ChartStudySpec } from "../../../time-series/types";
3
+ import { isLeverageFactor } from "../../../time-series/leverage";
4
+ import { priceComparisonSeriesIds } from "../../../time-series/price-comparison";
5
+ import { isUsListingExchange, parsePublicTickerKey } from "../../../utils/exchanges";
6
+ import { MAX_CHART_COMPOSER_SERIES } from "./chart-spec";
7
+ import { buildSeriesSpec, reconcilePanels } from "./chart-spec-edit";
8
+ import { normalizeInstrument } from "./series-expression";
9
+
10
+ /** A fund's daily objective as CMP draws it: `factor` times the index fund `proxy` each session. */
11
+ export interface DailyObjective {
12
+ factor: number;
13
+ proxy: string;
14
+ }
15
+
16
+ /** What CMP needs of a fund's facts: a daily objective with an index fund to draw it from. */
17
+ export interface LeverageFacts {
18
+ leverage?: { value: number; reset: string; proxy: { ticker: string } | null } | null;
19
+ }
20
+
21
+ export function dailyObjective(facts: LeverageFacts | null | undefined): DailyObjective | null {
22
+ const leverage = facts?.leverage;
23
+ if (!leverage || leverage.reset !== "daily" || !isLeverageFactor(leverage.value) || !leverage.proxy?.ticker) return null;
24
+ return { factor: leverage.value, proxy: leverage.proxy.ticker.toUpperCase() };
25
+ }
26
+
27
+ const LEVERAGE_STUDY_PREFIX = "leverage:";
28
+ const DECAY_STUDY_PREFIX = "leverage-decay:";
29
+
30
+ /** The bare ticker a compared leg is of (`TQQQ` for TQQQ:NASDAQ). */
31
+ function legTicker(series: ChartSeriesSpec): string | null {
32
+ return series.source.kind === "security" ? parsePublicTickerKey(series.source.instrument.symbol).symbol.toUpperCase() : null;
33
+ }
34
+
35
+ /** A ticker the fund facts read: US-listed, as its symbol is written there (SPY, BRK.B). */
36
+ const US_FUND_TICKER = /^[A-Z][A-Z0-9]{0,5}(?:\.[A-Z])?$/;
37
+
38
+ /** The US-listed tickers of a price comparison, whose facts can say they are leveraged funds. */
39
+ export function comparedFundTickers(spec: ChartSpec): string[] {
40
+ const compared = new Set(priceComparisonSeriesIds(spec) ?? []);
41
+ return [...new Set(spec.series.flatMap((series) => {
42
+ if (!compared.has(series.id) || series.source.kind !== "security") return [];
43
+ const exchange = series.source.instrument.exchange || parsePublicTickerKey(series.source.instrument.symbol).exchange;
44
+ const ticker = legTicker(series);
45
+ return ticker && US_FUND_TICKER.test(ticker) && (!exchange || isUsListingExchange(exchange)) ? [ticker] : [];
46
+ }))];
47
+ }
48
+
49
+ /** Whether the chart already draws a fund's objective, as built here or kept from before. */
50
+ function hasLeverageOverlay(spec: ChartSpec): boolean {
51
+ return spec.studies.some((study) => study.kind === "leverage" || study.kind === "leverage-decay");
52
+ }
53
+
54
+ /**
55
+ * Whether a report of this chart could draw a daily objective at all: a
56
+ * price comparison without one yet, over daily bars. One session's chart, or
57
+ * bars asked for by the week, month or hour, would only warn that the line
58
+ * needs daily bars, so its legs' facts are not asked for.
59
+ */
60
+ export function mayDrawDailyObjective(spec: ChartSpec): boolean {
61
+ if (hasLeverageOverlay(spec) || !priceComparisonSeriesIds(spec)) return false;
62
+ if (spec.viewport.range === "1D" && !spec.viewport.dateWindow) return false;
63
+ return spec.viewport.resolution === "auto" || spec.viewport.resolution === "1d";
64
+ }
65
+
66
+ /**
67
+ * A price comparison with each leveraged or inverse fund's daily objective
68
+ * drawn beside it: `factor` times its index fund each session, compounded
69
+ * from where the chart compares (3× daily QQQ beside TQQQ), with the index
70
+ * fund added as a leg when the chart has no room for it otherwise, and the
71
+ * fund's decay against that line and against the factor times the index
72
+ * fund's period return in a Decay panel. Any other chart, or a chart that
73
+ * already draws an objective, is returned as it was.
74
+ */
75
+ export function withLeverageOverlay(spec: ChartSpec, objectives: ReadonlyMap<string, DailyObjective>): ChartSpec {
76
+ const compared = priceComparisonSeriesIds(spec);
77
+ if (!compared || hasLeverageOverlay(spec) || objectives.size === 0) return spec;
78
+ const series = [...spec.series];
79
+ const studies: ChartStudySpec[] = [...spec.studies];
80
+ for (const fund of spec.series.filter((entry) => compared.includes(entry.id))) {
81
+ const objective = objectives.get(legTicker(fund) ?? "");
82
+ if (!objective || fund.source.kind !== "security") continue;
83
+ // A compared leg of the index fund, or the one added for another fund (TQQQ and SQQQ share QQQ).
84
+ let index = series.find((entry) => legTicker(entry) === objective.proxy && (compared.includes(entry.id) || !spec.series.includes(entry)));
85
+ if (!index) {
86
+ const instrument = normalizeInstrument(objective.proxy, true);
87
+ if (!instrument || series.length >= MAX_CHART_COMPOSER_SERIES) continue;
88
+ index = buildSeriesSpec({ kind: "security", ...instrument, fieldId: fund.source.fieldId }, series.length, {
89
+ style: fund.style, transform: fund.transform, axis: fund.axis, panelId: fund.panelId,
90
+ });
91
+ series.push(index);
92
+ }
93
+ const parameters = { factor: objective.factor };
94
+ studies.push(
95
+ { id: `${LEVERAGE_STUDY_PREFIX}${fund.id}`, kind: "leverage", inputSeriesIds: [index.id], parameters, panelId: fund.panelId, axis: "left" },
96
+ { id: `${DECAY_STUDY_PREFIX}${fund.id}`, kind: "leverage-decay", inputSeriesIds: [fund.id, index.id], parameters, panelId: "decay", axis: "auto" },
97
+ );
98
+ }
99
+ if (studies.length === spec.studies.length) return spec;
100
+ return { ...spec, series, studies, panels: reconcilePanels(spec.panels, series, studies) };
101
+ }
102
+
103
+ /** How long a comparison waits for its legs' fund facts before it is charted without objectives. */
104
+ const DAILY_OBJECTIVES_TIMEOUT_MS = 2_500;
105
+ /** A pane draws its chart meanwhile and adds the objectives when they come. */
106
+ export const LEVERAGE_FACTS_PANE_TIMEOUT_MS = 15_000;
107
+
108
+ /**
109
+ * Each compared fund's daily objective, from its facts. A fund whose facts
110
+ * fail to load, or are not in by `timeoutMs`, is charted without one: the
111
+ * comparison never waits long on them. The reads still running then are
112
+ * aborted through the signal `loadFacts` is given, as they are when `signal`
113
+ * (the caller's) aborts.
114
+ */
115
+ export async function loadDailyObjectives(
116
+ tickers: readonly string[],
117
+ loadFacts: (ticker: string, signal: AbortSignal) => Promise<LeverageFacts | null>,
118
+ { timeoutMs = DAILY_OBJECTIVES_TIMEOUT_MS, signal }: { timeoutMs?: number; signal?: AbortSignal } = {},
119
+ ): Promise<Map<string, DailyObjective>> {
120
+ const objectives = new Map<string, DailyObjective>();
121
+ if (tickers.length === 0) return objectives;
122
+ const deadline = new AbortController();
123
+ const expired = new Promise<null>((resolve) => deadline.signal.addEventListener("abort", () => resolve(null), { once: true }));
124
+ const timer = setTimeout(() => deadline.abort(new DOMException("Fund facts took too long.", "TimeoutError")), timeoutMs);
125
+ const cancel = () => deadline.abort(signal?.reason);
126
+ if (signal?.aborted) cancel();
127
+ else signal?.addEventListener("abort", cancel, { once: true });
128
+ try {
129
+ await Promise.all(tickers.map(async (ticker) => {
130
+ const facts = await Promise.race([loadFacts(ticker, deadline.signal).catch(logFailure("chart-composer.leverage-overlay", "Load chart fund objective failed", null)), expired]);
131
+ const objective = dailyObjective(facts);
132
+ // An index fund charted beside its leveraged fund is not leveraged itself.
133
+ if (objective && objective.proxy !== ticker) objectives.set(ticker, objective);
134
+ }));
135
+ } finally {
136
+ clearTimeout(timer);
137
+ signal?.removeEventListener("abort", cancel);
138
+ // Reads still running are no longer waited for.
139
+ deadline.abort();
140
+ }
141
+ return objectives;
142
+ }
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../../utils/log-failure";
1
2
  import { FINANCIAL_VINTAGE_NOTICE, SEC_EPS_BASIS_NOTICE } from "../../../utils/financial-statements";
2
3
  import { usePaneSharePreparation } from "../../../shares/prepare";
3
4
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
@@ -26,10 +27,13 @@ import type { PaneProps, TickerResearchTabProps } from "../../../types/plugin";
26
27
  import type { ChartResolution, TimeRange } from "../../../components/chart/core/types";
27
28
  import type { ChartSpec, ResolvedSeries } from "../../../time-series/types";
28
29
  import {
29
- getSupportedChartResolutionsForViewport,
30
+ getSupportedChartBarSizesForViewport,
30
31
  isIntradayResolution,
32
+ parseChartBarSize,
33
+ type ChartBarSize,
31
34
  type ManualChartResolution,
32
35
  } from "../../../time-series/resolution";
36
+ import { futuresSessionOpenMinute } from "../../../market-data/market/trading-sessions";
33
37
  import { useResolvedChartSpec } from "../../../time-series/hooks";
34
38
  import { shortCompanyName } from "../../../tickers/company-name";
35
39
  import { useSeriesListings } from "./series-listings";
@@ -52,13 +56,17 @@ import { colors } from "../../../theme/colors";
52
56
  import { isUsListingExchange, parsePublicTickerKey, publicTickerKey } from "../../../utils/exchanges";
53
57
  import { isMarketFieldId } from "../../../time-series/field-catalog";
54
58
  import { isDatasetChart } from "../../../time-series/spec";
59
+ import { seriesMessageName, studyMessageName } from "../../../time-series/series-name";
55
60
  import { CHART_COMPOSER_PANE_ID } from "../../../types/config";
56
61
  import { useRemoteUiNode } from "../../../remote/semantic-tree";
57
62
  import { SeriesEditorDialog } from "./editor";
58
63
  import { chartComposerSemanticMetadata } from "./semantic";
64
+ import { comparedFundTickers, LEVERAGE_FACTS_PANE_TIMEOUT_MS, loadDailyObjectives, withLeverageOverlay } from "./leverage-overlay";
65
+ import { loadFundFacts } from "../sec/fund-facts";
59
66
  import {
60
67
  canToggleChartSeries,
61
68
  CHART_INTERACTION_VIEWPORT_SETTING_KEY,
69
+ CHART_LEVERAGE_PENDING_SETTING_KEY,
62
70
  CHART_PINNED_MOMENT_SETTING_KEY,
63
71
  CHART_SPEC_SETTING_KEY,
64
72
  parseChartInteractionViewport,
@@ -106,11 +114,13 @@ import { buildEmptyChartPreset, buildPriceChartPreset } from "./presets";
106
114
  import type { ChartInteractionViewport } from "./chart-spec";
107
115
  import {
108
116
  CHART_FORMULA_OPTIONS,
117
+ CHART_BAR_SIZE_PRESETS,
109
118
  CHART_RANGES as RANGES,
110
- CHART_RESOLUTIONS as RESOLUTIONS,
119
+ CHART_RESOLUTIONS,
111
120
  chartStudyOptionsFor,
112
121
  chartStudyPeriodTitle,
113
122
  chartStudySettingLabel,
123
+ withChartBarSize,
114
124
  } from "./settings";
115
125
  import { resolveChartComposerShortcut } from "./shortcuts";
116
126
  import { describeChartResolution, formatChartDateWindow, formatChartResolution } from "./viewport-labels";
@@ -134,6 +144,9 @@ import { CHART_FOLLOW_SERIES_SETTING_KEY, rebindFollowChartSpec, resolveFollowSe
134
144
  import type { InstrumentRef } from "../../../market-data/request-types";
135
145
 
136
146
  const RANGE_OPTIONS = RANGES.map((range, index) => ({ label: range, value: range, hint: String(index + 1) }));
147
+ const SOURCE_BAR_SIZES = CHART_RESOLUTIONS.filter((value): value is ManualChartResolution => value !== "auto");
148
+ /** The bar size dialog's last choice, which asks for a size to type. */
149
+ const CUSTOM_BAR_SIZE_CHOICE = "custom";
137
150
  const AUTO_VIEWPORT_DEBOUNCE_MS = 350;
138
151
  /** A load for a moving view that has not answered in this long no longer holds the next one back. */
139
152
  const LOAD_AHEAD_TIMEOUT_MS = 4_000;
@@ -379,28 +392,46 @@ function ChartComposerSurface({
379
392
  const hasMarketSeries = spec.series.some((entry) => (
380
393
  entry.source.kind === "security" && isMarketFieldId(entry.source.fieldId)
381
394
  ));
382
- const availableResolutions = useMemo<ChartResolution[]>(() => {
395
+ // Bars built from a future's clock-aligned bars must not straddle its session's open.
396
+ const openMinute = useMemo(() => {
397
+ const listing = spec.series.find((entry) => entry.source.kind === "security" && isMarketFieldId(entry.source.fieldId));
398
+ return listing?.source.kind === "security" ? futuresSessionOpenMinute(listing.source.instrument.symbol, listing.source.instrument.exchange) : null;
399
+ }, [spec.series]);
400
+ // The sizes of `sizes` this chart can draw now, after Auto.
401
+ const availableOf = useCallback((sizes: readonly ChartBarSize[]): ChartResolution[] => {
383
402
  if (!resolution.resolutionSupport) {
384
403
  if (!hasMarketSeries) return ["auto"];
385
- if (!resolution.loading) return RESOLUTIONS;
404
+ if (!resolution.loading) return ["auto", ...sizes];
386
405
  return spec.viewport.resolution === "auto"
387
406
  ? ["auto"]
388
407
  : ["auto", spec.viewport.resolution];
389
408
  }
390
- const supported = new Set(getSupportedChartResolutionsForViewport(
409
+ return ["auto", ...getSupportedChartBarSizesForViewport(
391
410
  spec.viewport.range,
392
411
  resolution.resolutionSupport,
412
+ sizes,
393
413
  spec.viewport.dateWindow,
394
- ));
395
- return RESOLUTIONS.filter((value) => value === "auto" || supported.has(value));
414
+ openMinute,
415
+ )];
396
416
  }, [
397
417
  hasMarketSeries,
418
+ openMinute,
398
419
  resolution.loading,
399
420
  resolution.resolutionSupport,
400
421
  spec.viewport.dateWindow,
401
422
  spec.viewport.range,
402
423
  spec.viewport.resolution,
403
424
  ]);
425
+ // The bar lists the sizes sources serve, and a built one (4h) while the chart is set to it;
426
+ // the bar size dialog (b) lists the built ones too, and takes any other typed in.
427
+ const availableResolutions = useMemo(
428
+ () => availableOf(withChartBarSize(SOURCE_BAR_SIZES, spec.viewport.resolution)),
429
+ [availableOf, spec.viewport.resolution],
430
+ );
431
+ const dialogResolutions = useMemo(
432
+ () => availableOf(withChartBarSize(CHART_BAR_SIZE_PRESETS, spec.viewport.resolution)),
433
+ [availableOf, spec.viewport.resolution],
434
+ );
404
435
  // Auto names the bars it is on, which change as the view moves: a pan back
405
436
  // past where a source keeps 30-minute bars charts days instead.
406
437
  const autoBars = spec.viewport.resolution === "auto" ? resolution.resolution ?? null : null;
@@ -474,7 +505,15 @@ function ChartComposerSurface({
474
505
  () => listingRef.current,
475
506
  [freshListing?.seriesId, freshListing?.key, freshListing?.target.symbol, freshListing?.target.exchange],
476
507
  );
508
+ // The ticket's levels (its draft and working orders) move through the ticket, which reviews any change.
509
+ const tradeRef = useRef(trade);
510
+ tradeRef.current = trade;
477
511
  const editLevels = useCallback((edit: CompositeLevelEdit) => {
512
+ const ticket = tradeRef.current;
513
+ if (ticket?.levels.some((level) => level.id === edit.id)) {
514
+ if (edit.kind === "move") ticket.moveLevel?.(edit.id, edit.value);
515
+ return;
516
+ }
478
517
  const key = listingRef.current?.key;
479
518
  if (!key) return;
480
519
  setLevelStore((current: unknown) => {
@@ -578,7 +617,7 @@ function ChartComposerSurface({
578
617
  ]}
579
618
  />
580
619
  ),
581
- }).catch(() => undefined);
620
+ }).catch(logFailure("chart-composer.pane", "Open VWAP anchor choices failed"));
582
621
  if (choice === "pick") {
583
622
  pickAnchorAfterDialogRef.current = true;
584
623
  return { close: true };
@@ -594,7 +633,7 @@ function ChartComposerSurface({
594
633
  content: (ctx: PromptContext<string>) => (
595
634
  <TextPromptDialog {...ctx} title="Anchor VWAP at" placeholder="2026-09-30 or 2026-09-30 10:00" confirmLabel="Anchor" width={44} />
596
635
  ),
597
- }).catch(() => undefined);
636
+ }).catch(logFailure("chart-composer.pane", "Open VWAP date prompt failed"));
598
637
  if (!text) return;
599
638
  const anchor = parseVwapAnchor(text, anchorInputRef.current);
600
639
  if (anchor === null) {
@@ -661,6 +700,11 @@ function ChartComposerSurface({
661
700
  },
662
701
  onCancel: () => setPickingAnchor(false),
663
702
  } : null, [pickingAnchor, updateSpec]);
703
+ // The ticket beside the chart asks for a price: a press on the plot, or Enter at the cursor, sets it.
704
+ const tradeOnChart = !!trade && !!listing && researchTradeMatches(trade, { ...listing.instrument, exchange: listing.target.exchange });
705
+ const pricePick = useMemo(() => tradeOnChart && trade?.picking && trade.finishPick && trade.cancelPick ? {
706
+ label: `set ${trade.picking.label}`, onPick: trade.finishPick, onCancel: trade.cancelPick,
707
+ } : null, [tradeOnChart, trade?.picking, trade?.finishPick, trade?.cancelPick]);
664
708
  const formulasDialogRef = useRef<MultiSelectDialogButtonHandle | null>(null);
665
709
  const indicatorsDisabled = !isPriceStudyTarget(spec);
666
710
  const formulasDisabled = spec.series.filter((series) => series.visible !== false).length < 2;
@@ -830,7 +874,7 @@ function ChartComposerSurface({
830
874
  content: (context: PromptContext<ChartSpec | null>) => (
831
875
  <SeriesEditorDialog {...context} initialSpec={spec} />
832
876
  ),
833
- }).catch(() => null);
877
+ }).catch(logFailure("chart-composer.pane", "Open chart series editor failed", null));
834
878
  if (next) setSpec(next);
835
879
  } finally {
836
880
  setInteractionCaptured("prompt", false);
@@ -871,23 +915,57 @@ function ChartComposerSurface({
871
915
  content: (context: PromptContext<string>) => (
872
916
  <ChoiceDialog
873
917
  {...context}
874
- title="Chart Resolution"
918
+ title="Bar Size"
875
919
  selectedChoiceId={spec.viewport.resolution}
876
- choices={availableResolutions.map((value) => ({
877
- id: value,
878
- label: formatChartResolution(value),
879
- description: describeChartResolution(value),
880
- }))}
920
+ choices={[
921
+ ...dialogResolutions.map((value) => ({
922
+ id: value,
923
+ label: formatChartResolution(value),
924
+ description: describeChartResolution(value),
925
+ })),
926
+ ...(hasMarketSeries ? [{ id: CUSTOM_BAR_SIZE_CHOICE, label: "Custom…", description: "Type any number of minutes, hours, days, weeks or months." }] : []),
927
+ ]}
881
928
  />
882
929
  ),
883
- }).catch(() => "");
884
- if (availableResolutions.includes(next as ChartResolution)) setResolution(next as ChartResolution);
930
+ }).catch(logFailure("chart-composer.pane", "Open chart bar size choices failed", ""));
931
+ if (next === CUSTOM_BAR_SIZE_CHOICE) {
932
+ // A row picked with the mouse closes on mousedown; the field opens after the
933
+ // click has placed the focus, or the desktop leaves it on the dialog.
934
+ await new Promise((resolve) => setTimeout(resolve, 0));
935
+ const typed = await dialog.prompt<string>({
936
+ content: (ctx: PromptContext<string>) => (
937
+ <TextPromptDialog {...ctx} title="Custom Bar Size" placeholder="10m, 90m, 4h, 2D, 3W, 6mo" confirmLabel="Chart" width={44} />
938
+ ),
939
+ }).catch(logFailure("chart-composer.pane", "Open custom chart bar size prompt failed"));
940
+ if (!typed) return;
941
+ const size = parseChartBarSize(typed);
942
+ const count = /^\s*(\d+)\s*M\s*$/.exec(typed)?.[1];
943
+ if (!size) {
944
+ notify({
945
+ body: count
946
+ ? `Write ${count}m for ${count} minutes or ${count}mo for ${count} months.`
947
+ : `${typed} is not a bar size. Use a number and a unit: 10m, 4h, 2D, 3W, 6mo; up to a day of minutes or hours, a year of days or weeks, or 12 months.`,
948
+ type: "error",
949
+ });
950
+ return;
951
+ }
952
+ if (!availableOf(withChartBarSize([], size)).includes(size)) {
953
+ notify({ body: `${formatChartResolution(size)} bars are unavailable for this range.`, type: "error" });
954
+ return;
955
+ }
956
+ setResolution(size);
957
+ return;
958
+ }
959
+ if (dialogResolutions.includes(next as ChartResolution)) setResolution(next as ChartResolution);
885
960
  } finally {
886
961
  setInteractionCaptured("prompt", false);
887
962
  }
888
963
  }, [
889
- availableResolutions,
964
+ availableOf,
890
965
  dialog,
966
+ dialogResolutions,
967
+ hasMarketSeries,
968
+ notify,
891
969
  setInteractionCaptured,
892
970
  setResolution,
893
971
  spec.viewport.resolution,
@@ -923,7 +1001,7 @@ function ChartComposerSurface({
923
1001
  void openSeriesEditor();
924
1002
  return;
925
1003
  case "resolution":
926
- if (availableResolutions.length > 1) void openResolutionPicker();
1004
+ if (dialogResolutions.length > 1) void openResolutionPicker();
927
1005
  }
928
1006
  }, { enabled: focused && !dialogOpen });
929
1007
 
@@ -936,13 +1014,13 @@ function ChartComposerSurface({
936
1014
  const loading = resolution.loading || listings.pending;
937
1015
  // A bare code several companies list asks which, as `quote` does, before anything else is said.
938
1016
  const statusError = listings.errors[0] ?? resolution.errors[0];
939
- // A spread or formula error names its legs and their units; the study's id adds nothing to it.
1017
+ // A spread or formula error names its legs and their units; the study's name adds nothing to it.
940
1018
  const formulaStudy = spec.studies.find((study) => (study.kind === "spread" || study.kind === "formula")
941
- && statusError?.startsWith(`${study.id}: `));
942
- const statusErrorNotice = formulaStudy ? statusError?.slice(`${formulaStudy.id}: `.length) : statusError;
943
- // Failed series use their authored id in errors and their display label in warnings.
944
- const errorSeries = spec.series.find((entry) => statusError?.startsWith(`${entry.label ?? entry.id}: `));
945
- const errorMessage = errorSeries ? statusError?.slice(`${errorSeries.label ?? errorSeries.id}: `.length) : undefined;
1019
+ && statusError?.startsWith(`${studyMessageName(study)}: `));
1020
+ const statusErrorNotice = formulaStudy ? statusError?.slice(`${studyMessageName(formulaStudy)}: `.length) : statusError;
1021
+ // Failed series name what was asked for in errors and their display label in warnings.
1022
+ const errorSeries = spec.series.find((entry) => statusError?.startsWith(`${seriesMessageName(entry)}: `));
1023
+ const errorMessage = errorSeries ? statusError?.slice(`${seriesMessageName(errorSeries)}: `.length) : undefined;
946
1024
  // The label the resolver wrote its warnings with, before the legend named the company.
947
1025
  const errorSeriesLabel = (resolution.legendSeries?.find((entry) => entry.id === errorSeries?.id)
948
1026
  ?? legendSeries?.find((entry) => entry.id === errorSeries?.id))?.label;
@@ -965,9 +1043,9 @@ function ChartComposerSurface({
965
1043
  && !FORWARD_VALUATION_BASIS_NOTICES.has(warning)
966
1044
  && !duplicateErrorNotices.has(warning) && !comparisonEmptyNotices.has(warning)
967
1045
  && !spec.studies.some((study) => (
968
- (study.kind === "ratio" && warning.startsWith(`${study.id}: ratio inputs use different currencies (`)
1046
+ (study.kind === "ratio" && warning.startsWith(`${studyMessageName(study)}: ratio inputs use different currencies (`)
969
1047
  && warning.endsWith("); raw values are not FX-converted."))
970
- || (study.kind === "correlation" && warning.startsWith(`${study.id}: correlation mixes `)
1048
+ || (study.kind === "correlation" && warning.startsWith(`${studyMessageName(study)}: correlation mixes `)
971
1049
  && warning.endsWith("; only matching observation times contribute."))
972
1050
  ))
973
1051
  ));
@@ -1192,6 +1270,7 @@ function ChartComposerSurface({
1192
1270
  onToggleSeries={toggleSeries}
1193
1271
  isSeriesToggleable={isSeriesToggleable}
1194
1272
  timePick={timePick}
1273
+ pricePick={pricePick}
1195
1274
  levels={chartLevels}
1196
1275
  emptyMessage={emptyMessage}
1197
1276
  emptyDetail={emptyDetail}
@@ -1287,6 +1366,26 @@ export function ChartComposerPane({ paneId, focused, width, height }: PaneProps)
1287
1366
  savedForTarget.current = targetKey;
1288
1367
  }
1289
1368
  }, [follows, ownedIds, savedIds, setSpec, spec, stored, target, unlinkedFrom, updateSettings]);
1369
+ // A comparison CMP opened draws each leveraged or inverse fund's daily objective once its facts are read.
1370
+ const leveragePending = instance?.settings?.[CHART_LEVERAGE_PENDING_SETTING_KEY] === true;
1371
+ const storedRef = useRef(stored);
1372
+ storedRef.current = stored;
1373
+ useEffect(() => {
1374
+ if (!leveragePending) return;
1375
+ const mounted = new AbortController();
1376
+ // The chart draws meanwhile, so it can wait longer for them than a report does.
1377
+ void loadDailyObjectives(comparedFundTickers(storedRef.current),
1378
+ async (ticker, signal) => (await loadFundFacts(ticker, false, { signal })).payload,
1379
+ { timeoutMs: LEVERAGE_FACTS_PANE_TIMEOUT_MS, signal: mounted.signal })
1380
+ .then((objectives) => {
1381
+ if (mounted.signal.aborted) return;
1382
+ updateSettings({
1383
+ [CHART_SPEC_SETTING_KEY]: withLeverageOverlay(storedRef.current, objectives),
1384
+ [CHART_LEVERAGE_PENDING_SETTING_KEY]: undefined,
1385
+ });
1386
+ });
1387
+ return () => mounted.abort();
1388
+ }, [leveragePending, updateSettings]);
1290
1389
  if (follows && !target && ownedIds.length > 0) {
1291
1390
  return <EmptyState title={error ?? "Select a ticker."} />;
1292
1391
  }
@@ -391,6 +391,7 @@ function catalogFormula(expression: string): boolean {
391
391
  try {
392
392
  return parseFormulaExpression(expression) !== null;
393
393
  } catch {
394
+ // Intentional ignore: invalid catalog formulas are excluded from the chartable suggestions.
394
395
  return false;
395
396
  }
396
397
  }
@@ -1,4 +1,6 @@
1
1
  import { futuresGenericCaption, futuresGenericListing } from "../../../utils/futures-generic";
2
+ import { isIsoCurrencyCode } from "../../../utils/crypto-pair";
3
+ import { readTerminalListingCode } from "../../../tickers/terminal-codes";
2
4
  import type { ChartSeriesSpec, SeriesStyle, SeriesTransform } from "../../../time-series/types";
3
5
  import {
4
6
  canonicalTimeSeriesFieldId,
@@ -164,21 +166,78 @@ export function parseSeriesExpression(value: string): ParsedSeriesExpression | n
164
166
 
165
167
  const SERIES_FORMS = "Use SYMBOL, SYMBOL:field, FUT:code, UST:maturity, FRED:series, GEO:series, or CAP:capability-id:series-id.";
166
168
 
169
+ /** A word that reads as a series, not an operator or a number of a formula. */
170
+ const LIST_WORD = /^[A-Za-z^][\w.^=:/~-]*$/;
171
+
172
+ /** The words that close a Bloomberg security (`AAPL US Equity`, `EURUSD Curncy`), and its exchange code `US`. */
173
+ const BLOOMBERG_WORDS = new Set(["EQUITY", "INDEX", "CURNCY", "COMDTY", "GOVT", "CORP", "MTGE", "MUNI", "PFD"]);
174
+
175
+ /** Why words typed with spaces between them are no list of series, when they are not: what to say, if anything. */
176
+ interface NotAList {
177
+ hint?: string;
178
+ }
179
+
180
+ /**
181
+ * Words with spaces between them that are one thing and not tickers side by
182
+ * side: a Bloomberg security, a currency pair, or a series whose field has
183
+ * spaces in it (`MSFT:net income`). Charting each word would draw series
184
+ * nobody asked for, so these are errors, with a hint where one helps.
185
+ */
186
+ function notAList(words: readonly string[]): NotAList | null {
187
+ if (words.some((word, index) => BLOOMBERG_WORDS.has(word.toUpperCase()) || (index > 0 && word.toUpperCase() === "US"))) {
188
+ const code = readTerminalListingCode(words.join(" "));
189
+ return { hint: code ? ` That is a Bloomberg code: write it ${code.key}.` : " That is a Bloomberg security: write the ticker alone (AAPL), or with its exchange (AAPL:NASDAQ)." };
190
+ }
191
+ if (words.length === 2 && words.every((word) => /^[A-Za-z]{3}$/.test(word) && isIsoCurrencyCode(word.toUpperCase()))) {
192
+ const [base, quote] = words.map((word) => word.toUpperCase());
193
+ return { hint: ` ${base} ${quote} reads as a currency pair: write it ${base}/${quote}, or separate tickers with commas.` };
194
+ }
195
+ return words.some((word, index) => word.includes(":") && spacedField(words, index)) ? {} : null;
196
+ }
197
+
198
+ /** Whether the words from `start` on, joined, are one series whose field has spaces in it (`MSFT:net income`). */
199
+ function spacedField(words: readonly string[], start: number): boolean {
200
+ for (let end = start + 2; end <= words.length; end += 1) {
201
+ if (parseSeriesExpression(words.slice(start, end).join(" "))) return true;
202
+ }
203
+ return false;
204
+ }
205
+
206
+ /**
207
+ * One leg of a list: a series, or series typed with spaces between them
208
+ * (`AAPL MSFT`, as `fn G AAPL MSFT` passes them), each word a series of its
209
+ * own. Null when it is neither.
210
+ */
211
+ function parseLeg(leg: string): ParsedSeriesExpression[] | null {
212
+ const parsed = parseSeriesExpression(leg);
213
+ if (parsed) return [parsed];
214
+ const words = leg.trim().split(/\s+/);
215
+ if (words.length < 2 || notAList(words)) return null;
216
+ const series = words.map(parseSeriesExpression);
217
+ return series.every((entry): entry is ParsedSeriesExpression => entry != null) ? series : null;
218
+ }
219
+
167
220
  export function parseChartExpression(value: string): ParsedSeriesExpression[] {
168
221
  if (!value.trim()) return [];
169
222
  // A list pasted with a stray separator (`BRK.B,SPY,`, `,SPY`, `A,,B`) has no series between them.
170
223
  const legs = value.split(/[;,\n]/).filter((leg) => leg.trim());
171
224
  // Separators alone name no series at all.
172
225
  if (legs.length === 0) throw new Error(`Invalid chart series "${value.trim()}": no series between its separators. ${SERIES_FORMS}`);
173
- if (legs.length > MAX_CHART_COMPOSER_SERIES) {
174
- throw new Error(`Charts support up to ${MAX_CHART_COMPOSER_SERIES} base series.`);
175
- }
176
226
 
177
- return legs.map((leg) => {
178
- const parsed = parseSeriesExpression(leg);
227
+ const series = legs.flatMap((leg) => {
228
+ const parsed = parseLeg(leg);
179
229
  if (parsed) return parsed;
180
- throw new Error(`Invalid chart series "${leg.trim()}". ${SERIES_FORMS}`);
230
+ // Words with spaces between them that are not all series: a list is written with commas.
231
+ const words = leg.trim().split(/\s+/);
232
+ const reason = words.length > 1 ? notAList(words) : null;
233
+ const listHint = reason ? reason.hint ?? ""
234
+ : words.length > 1 && words.every((word) => LIST_WORD.test(word)) ? ` Separate series with commas: ${words.join(",")}.` : "";
235
+ throw new Error(`Invalid chart series "${leg.trim()}".${listHint} ${SERIES_FORMS}`);
181
236
  });
237
+ if (series.length > MAX_CHART_COMPOSER_SERIES) {
238
+ throw new Error(`Charts support up to ${MAX_CHART_COMPOSER_SERIES} base series.`);
239
+ }
240
+ return series;
182
241
  }
183
242
 
184
243
  export function formatSeriesExpression(series: ChartSeriesSpec): string {
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../../utils/log-failure";
1
2
  import type { DataProvider, MarketDataRequestContext } from "../../../types/data-provider";
2
3
  import type { PricePoint, Quote } from "../../../types/financials";
3
4
  import type { TimeRange } from "../../../time-series/range";
@@ -10,6 +11,7 @@ import {
10
11
  import { parsePublicTickerKey, resolveExchangeTimeZone } from "../../../utils/exchanges";
11
12
  import { listingSuffixExchange } from "../../../sources/listing-symbols";
12
13
  import { getPricePointTimestamp } from "../../../utils/price-history";
14
+ import { dateOptionError, readCalendarDate } from "../../../utils/calendar-date";
13
15
  import { pricePointIntegrity } from "../../../utils/price-history-integrity";
14
16
  import { zonedDateKey, zonedWallClockToUtcMs } from "../../../utils/zoned-date-time";
15
17
  import { fetchHistoryResult } from "../../../sources/history-result";
@@ -46,28 +48,22 @@ export interface LoadedIntradayWindow extends IntradayWindow {
46
48
  sourceKey?: string;
47
49
  }
48
50
 
49
- const DATE_ONLY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
50
51
  const HISTORICAL_RETRY_DELAY_MS = 61 * 60_000;
51
52
  const DAY_MS = 24 * 60 * 60_000;
52
53
 
54
+ /** `--session` as YYYY-MM-DD: any date a date option reads, or an error that lists the formats. */
55
+ function readSessionDate(value: string): string {
56
+ const date = readCalendarDate(value);
57
+ if (!date) throw new Error(`Invalid --session value "${value}". ${dateOptionError(value, "--session", { subject: "a session date" })}`);
58
+ return date;
59
+ }
60
+
53
61
  function parseSessionDate(value: string): {
54
62
  year: number;
55
63
  month: number;
56
64
  day: number;
57
65
  } {
58
- const match = DATE_ONLY_PATTERN.exec(value.trim());
59
- if (!match) throw new Error(`Invalid --session value "${value}". Use YYYY-MM-DD.`);
60
- const year = Number(match[1]);
61
- const month = Number(match[2]);
62
- const day = Number(match[3]);
63
- const candidate = new Date(Date.UTC(year, month - 1, day));
64
- if (
65
- candidate.getUTCFullYear() !== year
66
- || candidate.getUTCMonth() !== month - 1
67
- || candidate.getUTCDate() !== day
68
- ) {
69
- throw new Error(`Invalid --session value "${value}". Use a real calendar date.`);
70
- }
66
+ const [year, month, day] = value.split("-").map(Number) as [number, number, number];
71
67
  return { year, month, day };
72
68
  }
73
69
 
@@ -152,8 +148,7 @@ export function resolveIntradaySessionWindow(
152
148
  bySession.set(date, sessionPoints);
153
149
  }
154
150
 
155
- const requestedSession = options.session?.trim() || null;
156
- if (requestedSession) parseSessionDate(requestedSession);
151
+ const requestedSession = options.session?.trim() ? readSessionDate(options.session.trim()) : null;
157
152
  const availableSessions = [...bySession.keys()].sort();
158
153
  const selectedSessions = requestedSession
159
154
  ? availableSessions.filter((date) => date === requestedSession)
@@ -195,9 +190,8 @@ export function resolveIntradayRequest(options: {
195
190
  support?: readonly ChartResolutionSupport[];
196
191
  }): IntradayRequest {
197
192
  const session = typeof options.session === "string" && options.session.trim()
198
- ? options.session.trim()
193
+ ? readSessionDate(options.session.trim())
199
194
  : null;
200
- if (session) parseSessionDate(session);
201
195
  const rangePreset = session
202
196
  ? "1D"
203
197
  : options.rangePreset === "1W" ? "1W" : "1D";
@@ -254,13 +248,13 @@ async function loadHistoricalFallback(
254
248
  if (request.session) {
255
249
  const bounds = sessionUtcBounds(request.session, timeZone);
256
250
  return await fetchHistoryResult(provider, symbol, exchange,
257
- { kind: "detail", start: bounds.start, end: bounds.end, interval: request.resolution }, context).catch(() => null) ?? empty;
251
+ { kind: "detail", start: bounds.start, end: bounds.end, interval: request.resolution }, context).catch(logFailure("chart-composer.session-history", "Load requested intraday session failed", null)) ?? empty;
258
252
  }
259
253
  const end = new Date(now.getTime() - HISTORICAL_RETRY_DELAY_MS);
260
254
  const lookbackDays = request.rangePreset === "1W" ? 35 : 8;
261
255
  const start = new Date(end.getTime() - lookbackDays * DAY_MS);
262
256
  return await fetchHistoryResult(provider, symbol, exchange,
263
- { kind: "detail", start, end, interval: request.resolution }, context).catch(() => null) ?? empty;
257
+ { kind: "detail", start, end, interval: request.resolution }, context).catch(logFailure("chart-composer.session-history", "Load historical intraday fallback failed", null)) ?? empty;
264
258
  }
265
259
 
266
260
  export async function loadIntradayWindow(options: {
@@ -354,7 +348,7 @@ export async function loadIntradayWindow(options: {
354
348
  if (nonpositive.length) {
355
349
  // Metadata is needed only at this boundary. Do not infer a futures domain
356
350
  // from a ticker suffix, a contract multiplier, or an option security type.
357
- const reportedQuote = await options.provider.getQuote(options.symbol, options.exchange, options.context).catch(() => undefined);
351
+ const reportedQuote = await options.provider.getQuote(options.symbol, options.exchange, options.context).catch(logFailure("chart-composer.session-history", "Read intraday instrument metadata failed"));
358
352
  const quote = reportedQuote?.symbol.trim().toUpperCase() === options.symbol.trim().toUpperCase()
359
353
  ? reportedQuote : undefined;
360
354
  const instrumentType = quote?.instrumentType?.trim().toUpperCase() || null;