gloomberb 0.16.4 → 0.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (554) hide show
  1. package/README.md +14 -91
  2. package/package.json +4 -1
  3. package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
  4. package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
  5. package/src/account/billing.ts +57 -0
  6. package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
  7. package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
  8. package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
  9. package/src/account/session.ts +16 -0
  10. package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
  11. package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
  12. package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
  13. package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
  14. package/src/api-client/data.ts +24 -2
  15. package/src/api-client/earnings.ts +6 -0
  16. package/src/api-client/futures-curve.ts +56 -0
  17. package/src/api-client/index.ts +4 -1
  18. package/src/api-client/market-discovery.ts +10 -1
  19. package/src/api-client/paths.ts +7 -0
  20. package/src/api-client/research-activity.ts +15 -10
  21. package/src/api-client/types.ts +17 -1
  22. package/src/api-client/yield-curves.ts +8 -0
  23. package/src/app/global-shortcuts.ts +15 -1
  24. package/src/app/pane-runtime/ticker-open-runtime.ts +7 -3
  25. package/src/architecture/core-builtin-allowlist.json +4 -13
  26. package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
  27. package/src/capabilities/chart-series.ts +11 -1
  28. package/src/cli/commands/crypto-hints.ts +7 -0
  29. package/src/cli/commands/fred-series.ts +61 -0
  30. package/src/cli/commands/market.ts +407 -104
  31. package/src/cli/commands/news-hints.ts +62 -0
  32. package/src/cli/commands/news-search.ts +53 -0
  33. package/src/cli/commands/options-leaps.ts +5 -2
  34. package/src/cli/commands/overview.ts +93 -20
  35. package/src/cli/commands/remote.ts +2 -1
  36. package/src/cli/commands/search.ts +82 -9
  37. package/src/cli/commands/system.ts +55 -8
  38. package/src/cli/commands/ticker.ts +88 -11
  39. package/src/cli/context.ts +45 -14
  40. package/src/cli/desktop-pane-shot.ts +59 -7
  41. package/src/cli/earnings-calendar.ts +71 -0
  42. package/src/cli/freshness.ts +18 -7
  43. package/src/cli/glossary.ts +429 -0
  44. package/src/cli/history-rows.ts +48 -7
  45. package/src/cli/index-roots.ts +7 -0
  46. package/src/cli/index.ts +21 -7
  47. package/src/cli/known-gaps.ts +27 -0
  48. package/src/cli/listing-arg.ts +417 -56
  49. package/src/cli/not-a-ticker.ts +12 -5
  50. package/src/cli/pane-functions/access-gate.ts +5 -0
  51. package/src/cli/pane-functions/capabilities.ts +3 -2
  52. package/src/cli/pane-functions/catalog.ts +35 -5
  53. package/src/cli/pane-functions/data.ts +12 -8
  54. package/src/cli/pane-functions/discovery.ts +1 -0
  55. package/src/cli/pane-functions/dom.ts +20 -6
  56. package/src/cli/pane-functions/freshness.ts +363 -43
  57. package/src/cli/pane-functions/function-help.ts +12 -5
  58. package/src/cli/pane-functions/headless.ts +45 -17
  59. package/src/cli/pane-functions/index.ts +63 -10
  60. package/src/cli/pane-functions/market-session.ts +22 -8
  61. package/src/cli/pane-functions/options.ts +63 -22
  62. package/src/cli/pane-functions/report-notices.ts +25 -7
  63. package/src/cli/pane-functions/report.ts +15 -8
  64. package/src/cli/pane-functions/resolver.ts +49 -12
  65. package/src/cli/pane-functions/screenshot.ts +110 -23
  66. package/src/cli/report-tables.ts +3 -0
  67. package/src/cli/result.ts +4 -1
  68. package/src/cli/staged-tickers.ts +52 -0
  69. package/src/cli/symbol-args.ts +9 -0
  70. package/src/cli/symbol-list.ts +172 -0
  71. package/src/cli/ticker-resolution.ts +223 -30
  72. package/src/cli/types.ts +5 -0
  73. package/src/components/chart/composite/axis-overlays.tsx +6 -2
  74. package/src/components/chart/composite/composite-chart.tsx +40 -6
  75. package/src/components/chart/composite/legend.tsx +49 -2
  76. package/src/components/chart/composite/panel-surface.tsx +44 -17
  77. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  78. package/src/components/command-bar/panel/index.tsx +11 -3
  79. package/src/components/command-bar/panel/runtime.ts +3 -0
  80. package/src/components/command-bar/panel/types.ts +2 -0
  81. package/src/components/command-bar/routes/root/provider-search.ts +4 -3
  82. package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
  83. package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
  84. package/src/components/command-bar/workflow/tickers.ts +23 -4
  85. package/src/components/layout/detached-pane-shell.tsx +9 -0
  86. package/src/components/layout/floating-pane.tsx +3 -0
  87. package/src/components/layout/header.tsx +20 -5
  88. package/src/components/layout/pane/content.tsx +7 -13
  89. package/src/components/layout/pane/footer/index.tsx +6 -2
  90. package/src/components/layout/pane/footer/model.ts +35 -1
  91. package/src/components/layout/pane/header.tsx +24 -1
  92. package/src/components/layout/pane/index.tsx +12 -2
  93. package/src/components/layout/pane/sidebar.tsx +78 -10
  94. package/src/components/layout/shell/active-drag.ts +21 -5
  95. package/src/components/layout/shell/drag/index.ts +39 -9
  96. package/src/components/layout/shell/drag/live.ts +61 -51
  97. package/src/components/layout/shell/drag/runtime.ts +54 -12
  98. package/src/components/layout/shell/index.tsx +25 -7
  99. package/src/components/layout/shell/menu.ts +5 -0
  100. package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
  101. package/src/components/layout/shell/pane/layers.tsx +192 -45
  102. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
  103. package/src/components/markdown-text.tsx +62 -20
  104. package/src/components/metric-treemap/heat-surface.tsx +10 -1
  105. package/src/components/onboarding/account-step/form-panel.tsx +1 -1
  106. package/src/components/onboarding/account-step/index.tsx +1 -1
  107. package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
  108. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  109. package/src/components/onboarding/onboarding-keyboard.ts +1 -1
  110. package/src/components/onboarding/onboarding-wizard.tsx +2 -2
  111. package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
  112. package/src/components/onboarding/wizard-account.ts +2 -2
  113. package/src/components/pane-template-wizard.tsx +9 -1
  114. package/src/components/price-selector-dialog.tsx +11 -2
  115. package/src/components/sign-in-gate.tsx +3 -3
  116. package/src/components/ticker/list-table-view.tsx +24 -1
  117. package/src/components/ui/action-row.tsx +2 -1
  118. package/src/components/ui/button.tsx +7 -1
  119. package/src/components/ui/choice-dialog.tsx +6 -4
  120. package/src/components/ui/confirm-dialog.tsx +28 -18
  121. package/src/components/ui/data-table/index.tsx +17 -6
  122. package/src/components/ui/data-table/opentui/index.tsx +37 -6
  123. package/src/components/ui/data-table/types.ts +12 -0
  124. package/src/components/ui/dialog-actions.tsx +64 -0
  125. package/src/components/ui/display.tsx +17 -3
  126. package/src/components/ui/frame.tsx +35 -2
  127. package/src/components/ui/icon.tsx +2 -0
  128. package/src/components/ui/text-prompt-dialog.tsx +11 -9
  129. package/src/data/cached-query.ts +2 -0
  130. package/src/data/config/store/normalize.ts +7 -2
  131. package/src/data/ticker-repository.ts +5 -0
  132. package/src/data/ticker-store.ts +15 -0
  133. package/src/docs/content.ts +215 -0
  134. package/src/docs/load.ts +139 -0
  135. package/src/docs/requests.ts +39 -0
  136. package/src/docs/snapshot.chunk.ts +8 -0
  137. package/src/docs/snapshot.json +7416 -0
  138. package/src/docs/topics.ts +216 -0
  139. package/src/i18n/es.ts +61 -4
  140. package/src/i18n/ja.ts +61 -4
  141. package/src/i18n/ko.ts +61 -4
  142. package/src/i18n/zh-cn.ts +61 -4
  143. package/src/i18n/zh-tw.ts +61 -4
  144. package/src/layout/desks.ts +1 -1
  145. package/src/layout/pane-manager/dock-tree.ts +18 -0
  146. package/src/layout/pane-manager/index.ts +1 -0
  147. package/src/market-data/coordinator/chart.ts +10 -4
  148. package/src/market-data/coordinator/index.ts +6 -3
  149. package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
  150. package/src/market-data/futures-contract.ts +151 -0
  151. package/src/market-data/hooks.tsx +10 -2
  152. package/src/market-data/market/format.ts +39 -21
  153. package/src/market-data/market/freshness.ts +81 -18
  154. package/src/market-data/market/status.ts +19 -23
  155. package/src/market-data/published-apac-sessions.ts +23 -1
  156. package/src/market-data/quotes/contributions.ts +3 -0
  157. package/src/market-data/quotes/metadata.ts +7 -24
  158. package/src/market-data/quotes/resolution.ts +2 -0
  159. package/src/market-data/quotes/screener-live-quotes.ts +5 -4
  160. package/src/market-data/result-types.ts +2 -0
  161. package/src/plugins/builtin/account-management/model.ts +1 -56
  162. package/src/plugins/builtin/account-management/pane.tsx +6 -4
  163. package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
  164. package/src/plugins/builtin/alerts/cli.ts +313 -47
  165. package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
  166. package/src/plugins/builtin/alerts/events.ts +23 -2
  167. package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
  168. package/src/plugins/builtin/alerts/history.ts +2 -0
  169. package/src/plugins/builtin/alerts/index.tsx +41 -9
  170. package/src/plugins/builtin/alerts/pane.tsx +8 -0
  171. package/src/plugins/builtin/alerts/research-builder.ts +8 -3
  172. package/src/plugins/builtin/alerts/research-rules.ts +18 -2
  173. package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
  174. package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
  175. package/src/plugins/builtin/alerts/scheduled.ts +254 -0
  176. package/src/plugins/builtin/alerts/targets.ts +92 -0
  177. package/src/plugins/builtin/analytics/index.tsx +4 -2
  178. package/src/plugins/builtin/analytics/risk-headless.ts +30 -12
  179. package/src/plugins/builtin/analytics/risk-math.ts +91 -27
  180. package/src/plugins/builtin/analytics/risk-model.ts +35 -5
  181. package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
  182. package/src/plugins/builtin/attention/index.tsx +2 -0
  183. package/src/plugins/builtin/attention/pane.tsx +3 -1
  184. package/src/plugins/builtin/attention/series.ts +26 -0
  185. package/src/plugins/builtin/awards/index.tsx +2 -0
  186. package/src/plugins/builtin/awards/pane.tsx +3 -1
  187. package/src/plugins/builtin/awards/series.ts +29 -0
  188. package/src/plugins/builtin/bond-calculator/model.ts +2 -1
  189. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  190. package/src/plugins/builtin/cds/client.ts +70 -13
  191. package/src/plugins/builtin/cds/headless.ts +116 -19
  192. package/src/plugins/builtin/cds/index.tsx +3 -1
  193. package/src/plugins/builtin/cds/model.ts +193 -31
  194. package/src/plugins/builtin/cds/pane.tsx +56 -14
  195. package/src/plugins/builtin/cds/series.ts +19 -0
  196. package/src/plugins/builtin/central-bank-rates/index.tsx +2 -0
  197. package/src/plugins/builtin/central-bank-rates/series.ts +42 -0
  198. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +192 -255
  199. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
  200. package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
  201. package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
  202. package/src/plugins/builtin/chart-composer/headless.ts +8 -3
  203. package/src/plugins/builtin/chart-composer/index.tsx +9 -2
  204. package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
  205. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
  206. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
  207. package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
  208. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
  209. package/src/plugins/builtin/chat/controller/index.ts +2 -0
  210. package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
  211. package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
  212. package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
  213. package/src/plugins/builtin/cloud/askg/model.ts +27 -8
  214. package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
  215. package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
  216. package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
  217. package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
  218. package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
  219. package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
  220. package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
  221. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
  222. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
  223. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
  224. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
  225. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
  226. package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
  227. package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
  228. package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
  229. package/src/plugins/builtin/company-attention/headless.ts +19 -5
  230. package/src/plugins/builtin/company-attention/index.tsx +2 -0
  231. package/src/plugins/builtin/company-attention/model.ts +26 -7
  232. package/src/plugins/builtin/company-attention/pane.tsx +12 -9
  233. package/src/plugins/builtin/company-attention/series.ts +52 -0
  234. package/src/plugins/builtin/company-kpis/pane.tsx +4 -2
  235. package/src/plugins/builtin/composite-plugins.ts +19 -13
  236. package/src/plugins/builtin/cot/index.tsx +3 -1
  237. package/src/plugins/builtin/cot/model.ts +40 -11
  238. package/src/plugins/builtin/cot/series.ts +27 -0
  239. package/src/plugins/builtin/credit-boards/index.tsx +2 -0
  240. package/src/plugins/builtin/credit-boards/series.ts +66 -0
  241. package/src/plugins/builtin/credit-conditions/index.tsx +2 -0
  242. package/src/plugins/builtin/credit-conditions/series.ts +26 -0
  243. package/src/plugins/builtin/credit-documents/headless.ts +31 -1
  244. package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
  245. package/src/plugins/builtin/crypto-board/headless.ts +2 -3
  246. package/src/plugins/builtin/crypto-board/index.tsx +2 -0
  247. package/src/plugins/builtin/crypto-board/model.ts +12 -0
  248. package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
  249. package/src/plugins/builtin/crypto-board/series.ts +48 -0
  250. package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
  251. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  252. package/src/plugins/builtin/debt-maturities/series.ts +45 -0
  253. package/src/plugins/builtin/dividend-yield/headless.ts +2 -2
  254. package/src/plugins/builtin/dividend-yield/index.tsx +2 -0
  255. package/src/plugins/builtin/dividend-yield/series.ts +20 -0
  256. package/src/plugins/builtin/docs/blocks.tsx +181 -0
  257. package/src/plugins/builtin/docs/index.tsx +68 -0
  258. package/src/plugins/builtin/docs/pane.tsx +426 -0
  259. package/src/plugins/builtin/docs/targets.ts +72 -0
  260. package/src/plugins/builtin/docs/use-docs.ts +60 -0
  261. package/src/plugins/builtin/doe/index.tsx +2 -0
  262. package/src/plugins/builtin/doe/series.ts +62 -0
  263. package/src/plugins/builtin/earnings/client.ts +3 -2
  264. package/src/plugins/builtin/earnings/format.ts +1 -5
  265. package/src/plugins/builtin/earnings/headless.ts +58 -6
  266. package/src/plugins/builtin/earnings/history-model.ts +15 -1
  267. package/src/plugins/builtin/earnings/history-table.ts +13 -2
  268. package/src/plugins/builtin/earnings/history.tsx +7 -3
  269. package/src/plugins/builtin/econ/fred-catalog.ts +189 -0
  270. package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
  271. package/src/plugins/builtin/econ/index.tsx +2 -0
  272. package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
  273. package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
  274. package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
  275. package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
  276. package/src/plugins/builtin/exposure/holdings.ts +1 -1
  277. package/src/plugins/builtin/exposure/pane.tsx +3 -1
  278. package/src/plugins/builtin/fear-greed/index.tsx +4 -0
  279. package/src/plugins/builtin/fear-greed/series.ts +52 -0
  280. package/src/plugins/builtin/futures/index.tsx +43 -3
  281. package/src/plugins/builtin/futures/model.ts +1 -1
  282. package/src/plugins/builtin/futures/returns.ts +1 -1
  283. package/src/plugins/builtin/futures/series.ts +13 -0
  284. package/src/plugins/builtin/futures/table.tsx +1 -1
  285. package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
  286. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  287. package/src/plugins/builtin/futures-curve/headless.ts +70 -9
  288. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  289. package/src/plugins/builtin/futures-curve/model.ts +66 -11
  290. package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
  291. package/src/plugins/builtin/fx-matrix/index.tsx +1 -1
  292. package/src/plugins/builtin/gpu/board.tsx +13 -10
  293. package/src/plugins/builtin/gpu/changes.tsx +4 -4
  294. package/src/plugins/builtin/gpu/client.ts +19 -1
  295. package/src/plugins/builtin/gpu/equities.tsx +14 -10
  296. package/src/plugins/builtin/gpu/headless.ts +56 -25
  297. package/src/plugins/builtin/gpu/history.tsx +3 -3
  298. package/src/plugins/builtin/gpu/index.tsx +2 -0
  299. package/src/plugins/builtin/gpu/model.ts +101 -16
  300. package/src/plugins/builtin/gpu/pane.tsx +28 -12
  301. package/src/plugins/builtin/gpu/series.ts +38 -0
  302. package/src/plugins/builtin/help/function-card.tsx +25 -6
  303. package/src/plugins/builtin/help/index.tsx +17 -8
  304. package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
  305. package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
  306. package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
  307. package/src/plugins/builtin/holders/client.ts +22 -3
  308. package/src/plugins/builtin/holders/format.ts +18 -3
  309. package/src/plugins/builtin/holders/headless.ts +36 -133
  310. package/src/plugins/builtin/holders/pane.tsx +11 -4
  311. package/src/plugins/builtin/holders/report-header.ts +40 -5
  312. package/src/plugins/builtin/holders/report-rows.ts +240 -0
  313. package/src/plugins/builtin/insider/client.ts +35 -20
  314. package/src/plugins/builtin/insider/headless.ts +41 -11
  315. package/src/plugins/builtin/insider/index.tsx +26 -9
  316. package/src/plugins/builtin/insider/insider-data.ts +10 -0
  317. package/src/plugins/builtin/insider/issuer.ts +49 -0
  318. package/src/plugins/builtin/insider/model.ts +3 -0
  319. package/src/plugins/builtin/iv-history/client.ts +14 -4
  320. package/src/plugins/builtin/iv-history/headless.ts +7 -4
  321. package/src/plugins/builtin/iv-history/index.tsx +2 -0
  322. package/src/plugins/builtin/iv-history/model.ts +111 -7
  323. package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
  324. package/src/plugins/builtin/iv-history/series.ts +29 -0
  325. package/src/plugins/builtin/jobs/headless.ts +28 -3
  326. package/src/plugins/builtin/jobs/index.tsx +3 -1
  327. package/src/plugins/builtin/jobs/series.ts +19 -0
  328. package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
  329. package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
  330. package/src/plugins/builtin/macro-day/client.ts +44 -3
  331. package/src/plugins/builtin/macro-day/headless.ts +13 -10
  332. package/src/plugins/builtin/macro-day/model.ts +56 -10
  333. package/src/plugins/builtin/macro-day/pane.tsx +30 -20
  334. package/src/plugins/builtin/market-heatmap/model.ts +19 -11
  335. package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
  336. package/src/plugins/builtin/market-movers/client.ts +7 -5
  337. package/src/plugins/builtin/market-movers/index.tsx +3 -2
  338. package/src/plugins/builtin/market-movers/model.ts +30 -0
  339. package/src/plugins/builtin/market-movers/screener.ts +31 -0
  340. package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
  341. package/src/plugins/builtin/market-valuation/index.tsx +3 -3
  342. package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
  343. package/src/plugins/builtin/members/headless.ts +7 -2
  344. package/src/plugins/builtin/members/model.ts +31 -3
  345. package/src/plugins/builtin/members/pane.tsx +3 -6
  346. package/src/plugins/builtin/mna/headless.ts +15 -3
  347. package/src/plugins/builtin/money-markets/index.tsx +2 -0
  348. package/src/plugins/builtin/money-markets/series.ts +41 -0
  349. package/src/plugins/builtin/notes/cli.ts +12 -7
  350. package/src/plugins/builtin/options/view.tsx +1 -1
  351. package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
  352. package/src/plugins/builtin/options-positioning/client.ts +7 -3
  353. package/src/plugins/builtin/options-positioning/headless.ts +1 -0
  354. package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
  355. package/src/plugins/builtin/options-scenario/client.ts +2 -1
  356. package/src/plugins/builtin/options-scenario/headless.ts +1 -0
  357. package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
  358. package/src/plugins/builtin/perps/client.ts +40 -6
  359. package/src/plugins/builtin/perps/equity-row.tsx +33 -11
  360. package/src/plugins/builtin/perps/freshness.ts +66 -0
  361. package/src/plugins/builtin/perps/headless.ts +45 -30
  362. package/src/plugins/builtin/perps/index.tsx +18 -1
  363. package/src/plugins/builtin/perps/model.ts +20 -5
  364. package/src/plugins/builtin/perps/pane.tsx +76 -20
  365. package/src/plugins/builtin/perps/series.ts +76 -0
  366. package/src/plugins/builtin/plugin-marketplace/pane.tsx +67 -61
  367. package/src/plugins/builtin/plugin-module.ts +3 -0
  368. package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
  369. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +273 -0
  370. package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
  371. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +331 -65
  372. package/src/plugins/builtin/portfolio-list/cli/render.ts +200 -31
  373. package/src/plugins/builtin/portfolio-list/cli/shared.ts +24 -0
  374. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -47
  375. package/src/plugins/builtin/portfolio-list/column-values.ts +1 -1
  376. package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
  377. package/src/plugins/builtin/portfolio-list/headless.ts +34 -4
  378. package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
  379. package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
  380. package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -1
  381. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +17 -1
  382. package/src/plugins/builtin/portfolio-list/summary/totals.ts +1 -1
  383. package/src/plugins/builtin/portfolio-list/table.tsx +7 -1
  384. package/src/plugins/builtin/power/client.ts +16 -0
  385. package/src/plugins/builtin/power/evidence.ts +6 -2
  386. package/src/plugins/builtin/power/headless.ts +71 -7
  387. package/src/plugins/builtin/power/index.tsx +4 -1
  388. package/src/plugins/builtin/power/model.ts +72 -1
  389. package/src/plugins/builtin/power/pane.tsx +32 -9
  390. package/src/plugins/builtin/rate-path/headless.ts +11 -3
  391. package/src/plugins/builtin/realized-vol/headless.ts +5 -0
  392. package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
  393. package/src/plugins/builtin/research/event-model.ts +68 -24
  394. package/src/plugins/builtin/research/events-headless.ts +2 -1
  395. package/src/plugins/builtin/research/headless.ts +2 -1
  396. package/src/plugins/builtin/seasonality/client.ts +15 -7
  397. package/src/plugins/builtin/seasonality/headless.ts +36 -12
  398. package/src/plugins/builtin/seasonality/index.tsx +2 -2
  399. package/src/plugins/builtin/seasonality/model.ts +119 -0
  400. package/src/plugins/builtin/seasonality/pane.tsx +108 -37
  401. package/src/plugins/builtin/series-inventory.ts +91 -0
  402. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
  403. package/src/plugins/builtin/shared/command-tab.ts +30 -12
  404. package/src/plugins/builtin/shared/earnings-report.ts +55 -0
  405. package/src/plugins/builtin/shared/fred-points.ts +20 -0
  406. package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
  407. package/src/plugins/builtin/shared/open-description.ts +29 -0
  408. package/src/plugins/builtin/shared/report-freshness.ts +9 -0
  409. package/src/plugins/builtin/shared/series-warning.ts +5 -0
  410. package/src/plugins/builtin/short-interest/headless.ts +1 -0
  411. package/src/plugins/builtin/short-interest/index.tsx +2 -0
  412. package/src/plugins/builtin/short-interest/series.ts +36 -0
  413. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  414. package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
  415. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  416. package/src/plugins/builtin/short-volume/index.tsx +2 -0
  417. package/src/plugins/builtin/short-volume/series.ts +23 -0
  418. package/src/plugins/builtin/social-mentions/index.tsx +2 -0
  419. package/src/plugins/builtin/social-mentions/series.ts +23 -0
  420. package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
  421. package/src/plugins/builtin/supply-chain/pane.tsx +3 -1
  422. package/src/plugins/builtin/thirteenf/api.ts +1 -0
  423. package/src/plugins/builtin/thirteenf/data.ts +6 -4
  424. package/src/plugins/builtin/thirteenf/headless.ts +217 -36
  425. package/src/plugins/builtin/thirteenf/model.ts +39 -1
  426. package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
  427. package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
  428. package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
  429. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  430. package/src/plugins/builtin/ticker-detail/index.tsx +3 -0
  431. package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
  432. package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
  433. package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
  434. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
  435. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +48 -4
  436. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
  437. package/src/plugins/builtin/time-sales/headless.ts +1 -0
  438. package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
  439. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  440. package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
  441. package/src/plugins/builtin/vol-surface/headless.ts +1 -0
  442. package/src/plugins/builtin/volatility/index.tsx +2 -0
  443. package/src/plugins/builtin/volatility/series.ts +84 -0
  444. package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
  445. package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
  446. package/src/plugins/builtin/world-venue-map/index.ts +2 -1
  447. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +8 -4
  448. package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
  449. package/src/plugins/builtin/yield-curve/chart.ts +2 -2
  450. package/src/plugins/builtin/yield-curve/curves.ts +21 -8
  451. package/src/plugins/builtin/yield-curve/headless.ts +71 -18
  452. package/src/plugins/builtin/yield-curve/index.tsx +3 -1
  453. package/src/plugins/builtin/yield-curve/series.ts +86 -0
  454. package/src/plugins/catalog-browser.ts +2 -1
  455. package/src/plugins/registry/index.ts +89 -4
  456. package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
  457. package/src/portfolio/position-value.ts +40 -0
  458. package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
  459. package/src/public/time-series.ts +17 -0
  460. package/src/react/auto-refresh.ts +13 -3
  461. package/src/remote/app-host.tsx +20 -4
  462. package/src/remote/confirm-change.tsx +85 -0
  463. package/src/remote/controller-utils.ts +8 -1
  464. package/src/remote/controller.ts +123 -6
  465. package/src/remote/pane-screenshot.ts +47 -0
  466. package/src/remote/schema.ts +62 -0
  467. package/src/remote/types.ts +30 -0
  468. package/src/remote/watchlist.ts +306 -0
  469. package/src/renderers/browser/main.tsx +3 -2
  470. package/src/renderers/cloudflare/worker.ts +1 -1
  471. package/src/renderers/dom/data-table/frozen-column.ts +3 -1
  472. package/src/renderers/dom/data-table/index.tsx +33 -6
  473. package/src/renderers/dom/data-table/row.tsx +27 -1
  474. package/src/renderers/dom/desktop/control-styles.ts +63 -1
  475. package/src/renderers/dom/desktop/controls.tsx +30 -23
  476. package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
  477. package/src/renderers/dom/desktop/icons.tsx +7 -0
  478. package/src/renderers/dom/dom-ui-host.tsx +3 -0
  479. package/src/renderers/dom/host/box.tsx +3 -0
  480. package/src/renderers/dom/host/chart-surface.tsx +6 -2
  481. package/src/renderers/dom/host/live-frame.ts +6 -2
  482. package/src/renderers/dom/host/overflow-fade.ts +14 -1
  483. package/src/renderers/dom/host/size-observer.ts +26 -0
  484. package/src/renderers/dom/host/surface-3d.tsx +7 -2
  485. package/src/renderers/dom/host/text.tsx +1 -1
  486. package/src/renderers/dom/styles.css +61 -0
  487. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +17 -2
  488. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +19 -11
  489. package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
  490. package/src/renderers/electrobun/view/main.tsx +2 -0
  491. package/src/series/capability.ts +75 -0
  492. package/src/series/csv.ts +160 -0
  493. package/src/series/files.ts +107 -0
  494. package/src/series/registry.ts +198 -0
  495. package/src/series/resolve.ts +107 -0
  496. package/src/series/standalone.ts +48 -0
  497. package/src/series/types.ts +145 -0
  498. package/src/series/validate.ts +171 -0
  499. package/src/sources/gloomberb-cloud/index.ts +7 -7
  500. package/src/sources/gloomberb-cloud/normalizers.ts +1 -0
  501. package/src/sources/history-result.ts +1 -0
  502. package/src/sources/listing-symbols.ts +4 -1
  503. package/src/sources/provider-router/batches.ts +4 -1
  504. package/src/sources/provider-router/cache.ts +4 -2
  505. package/src/sources/provider-router/cached-routes.ts +1 -1
  506. package/src/sources/provider-router/financial-routes.ts +1 -0
  507. package/src/sources/provider-router/financials.ts +13 -0
  508. package/src/sources/provider-router/history.ts +43 -25
  509. package/src/sources/provider-router/search.ts +1 -0
  510. package/src/sync/core-contributors.ts +1 -0
  511. package/src/tickers/company-name.ts +75 -0
  512. package/src/tickers/instrument-kind.ts +25 -0
  513. package/src/tickers/open-target.ts +3 -2
  514. package/src/tickers/search/index.ts +45 -7
  515. package/src/tickers/search/ranking.ts +33 -17
  516. package/src/tickers/search/types.ts +7 -1
  517. package/src/tickers/us-listing.ts +34 -0
  518. package/src/time-series/hooks.ts +9 -0
  519. package/src/time-series/resolve.ts +95 -16
  520. package/src/time-series/types.ts +4 -2
  521. package/src/time-series/use-chart-resolution.ts +32 -0
  522. package/src/types/config.ts +6 -0
  523. package/src/types/data-provider.ts +5 -0
  524. package/src/types/financials.ts +52 -1
  525. package/src/types/headless.ts +61 -0
  526. package/src/types/plugin.ts +19 -0
  527. package/src/types/price-history.ts +7 -0
  528. package/src/types/ticker.ts +14 -0
  529. package/src/ui/host.tsx +18 -0
  530. package/src/ui/live-resize.ts +81 -0
  531. package/src/ui/live-stretch.ts +121 -0
  532. package/src/ui/measured-cells.ts +58 -0
  533. package/src/ui/pane-fill.ts +11 -0
  534. package/src/utils/basis-points.ts +17 -0
  535. package/src/utils/cli-output.ts +7 -1
  536. package/src/utils/concurrency.ts +25 -0
  537. package/src/utils/crypto-pair.ts +20 -0
  538. package/src/utils/currency-pair.ts +19 -0
  539. package/src/utils/decimal-comma.ts +19 -0
  540. package/src/utils/dom-screenshot-css.ts +265 -0
  541. package/src/utils/dom-screenshot-rasters.ts +276 -0
  542. package/src/utils/dom-screenshot.ts +437 -52
  543. package/src/utils/exchange-rate-snapshot.ts +6 -2
  544. package/src/utils/exchanges.ts +107 -1
  545. package/src/utils/format.ts +16 -3
  546. package/src/utils/fundamentals.ts +66 -0
  547. package/src/utils/futures-generic.ts +6 -12
  548. package/src/utils/fx-market-hours.ts +15 -5
  549. package/src/utils/price-history.ts +99 -42
  550. package/src/utils/sec-eps-basis.ts +24 -11
  551. package/src/utils/sec.ts +61 -7
  552. package/src/utils/utc-time.ts +51 -4
  553. package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
  554. /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
@@ -12,7 +12,7 @@ import {
12
12
  } from "../../../components";
13
13
  import type { PaneProps } from "../../../types/plugin";
14
14
  import { colors } from "../../../theme/colors";
15
- import { compareSortValues, nextHeaderSort, type SortDirection } from "../../../utils/sort-values";
15
+ import { nextHeaderSort, type SortDirection } from "../../../utils/sort-values";
16
16
  import { isPlainArrowUp, stopSearchFocusNavigation } from "../../../utils/search-focus-navigation";
17
17
  import { usePaneSettingValue } from "../../../state/app/context";
18
18
  import { usePluginAppActions, usePluginPaneState } from "../../runtime";
@@ -20,22 +20,28 @@ import { usePaneStatusLinkFooter } from "../../../components/layout/pane/status-
20
20
  import { PaneTemplateInputStep } from "../../../components/pane-template-wizard";
21
21
  import { type PromptContext, useDialog } from "../../../ui/dialog";
22
22
  import {
23
- CATALOG_FILTERS,
24
23
  CHART_COMPOSER_TEMPLATE_ID,
25
24
  DATA_CATALOG_PANE_ID,
26
25
  catalogEmptyCopy,
27
26
  catalogExpressionForRow,
28
27
  catalogInstrumentMatchesQuery,
28
+ catalogRowsForListedCrypto,
29
29
  catalogRowsForResolvedInstruments,
30
+ catalogRowsFromEntries,
31
+ catalogTabs,
32
+ compareCatalogGroups,
33
+ compareCatalogText,
30
34
  filterCatalogRows,
31
- listStaticCatalogInventory,
35
+ frequencyRank,
32
36
  looksLikeCatalogTickerQuery,
37
+ mergeCatalogRows,
38
+ normalizeCatalogFilter,
33
39
  type CatalogFilterId,
34
40
  type CatalogSeriesRow,
35
41
  } from "./catalog-inventory";
36
- import { useCatalogUniverse } from "./use-series-catalog";
42
+ import { useCatalogUniverse, useRegisteredSeries } from "./use-series-catalog";
37
43
 
38
- type CatalogColumnId = "series" | "publisher" | "kind" | "expression";
44
+ type CatalogColumnId = "series" | "group" | "unit" | "frequency" | "publisher" | "expression";
39
45
  type CatalogColumn = DataTableColumn & { id: CatalogColumnId };
40
46
 
41
47
  interface CatalogSortPreference {
@@ -43,32 +49,59 @@ interface CatalogSortPreference {
43
49
  direction: SortDirection;
44
50
  }
45
51
 
46
- const DEFAULT_SORT: CatalogSortPreference = { columnId: "publisher", direction: "asc" };
52
+ const DEFAULT_SORT: CatalogSortPreference = { columnId: "group", direction: "asc" };
47
53
 
48
- function sortValue(columnId: CatalogColumnId, row: CatalogSeriesRow): string | null {
54
+ const FREQUENCY_LABELS: Record<CatalogSeriesRow["frequency"], string> = {
55
+ intraday: "Intraday",
56
+ daily: "Daily",
57
+ weekly: "Weekly",
58
+ monthly: "Monthly",
59
+ quarterly: "Quarterly",
60
+ annual: "Annual",
61
+ irregular: "Irregular",
62
+ };
63
+
64
+ function compareRows(columnId: CatalogColumnId, left: CatalogSeriesRow, right: CatalogSeriesRow): number {
49
65
  switch (columnId) {
50
66
  case "series":
51
- return row.label;
67
+ return compareCatalogText(left.label, right.label);
68
+ case "group":
69
+ return compareCatalogGroups(left.group, right.group);
70
+ case "unit":
71
+ return compareCatalogText(left.unit, right.unit);
72
+ case "frequency":
73
+ return frequencyRank(left.frequency) - frequencyRank(right.frequency);
52
74
  case "publisher":
53
- // Blank publishers (market data) sort after the named ones.
54
- return row.publisher || null;
55
- case "kind":
56
- return row.kind;
75
+ // Blank publishers (market data) sort after the named ones, either way.
76
+ if (!left.publisher || !right.publisher) return 0;
77
+ return compareCatalogText(left.publisher, right.publisher);
57
78
  case "expression":
58
- return row.expression;
79
+ return compareCatalogText(left.expression, right.expression);
59
80
  }
60
81
  }
61
82
 
62
- function buildColumns(width: number): CatalogColumn[] {
63
- const publisherWidth = 10;
64
- const kindWidth = 12;
65
- const expressionWidth = Math.min(28, Math.max(16, Math.floor(width * 0.28)));
66
- return [
83
+ function sortRows(rows: CatalogSeriesRow[], { columnId, direction }: CatalogSortPreference): CatalogSeriesRow[] {
84
+ // Rows arrive in the default order, so the default sort is free.
85
+ if (columnId === DEFAULT_SORT.columnId && direction === DEFAULT_SORT.direction) return rows;
86
+ const sign = direction === "asc" ? 1 : -1;
87
+ return [...rows].sort((left, right) => {
88
+ if (columnId === "publisher" && !left.publisher !== !right.publisher) return left.publisher ? -1 : 1;
89
+ return sign * compareRows(columnId, left, right) || left.order - right.order;
90
+ });
91
+ }
92
+
93
+ /** The table keeps the series name and its expression; the rest fold away as the pane narrows. */
94
+ function buildColumns(width: number, showGroup: boolean): CatalogColumn[] {
95
+ const expressionWidth = Math.min(30, Math.max(16, Math.floor(width * 0.26)));
96
+ const columns: CatalogColumn[] = [
67
97
  { id: "series", label: "SERIES", width: 18, flexGrow: 1, align: "left" },
68
- { id: "publisher", label: "PUBLISHER", width: publisherWidth, align: "left" },
69
- { id: "kind", label: "KIND", width: kindWidth, align: "left" },
70
- { id: "expression", label: "EXPRESSION", width: expressionWidth, align: "left" },
71
98
  ];
99
+ if (showGroup && width >= 70) columns.push({ id: "group", label: "KIND", width: 12, align: "left" });
100
+ if (width >= 84) columns.push({ id: "unit", label: "UNIT", width: 10, align: "left" });
101
+ if (width >= 96) columns.push({ id: "frequency", label: "FREQ", width: 9, align: "left" });
102
+ if (width >= 60) columns.push({ id: "publisher", label: "PUBLISHER", width: 10, align: "left" });
103
+ columns.push({ id: "expression", label: "EXPRESSION", width: expressionWidth, align: "left" });
104
+ return columns;
72
105
  }
73
106
 
74
107
  export function DataCatalogPane({ focused, width, height }: PaneProps) {
@@ -76,11 +109,14 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
76
109
  const dialog = useDialog();
77
110
  const [seedQuery] = usePaneSettingValue("query", "");
78
111
  const [searchQuery, setSearchQuery] = useState(seedQuery);
79
- const [filter, setFilter] = usePluginPaneState<CatalogFilterId>("activeTab", "all");
112
+ const [savedFilter, setFilter] = usePluginPaneState<CatalogFilterId>("activeTab", "all");
80
113
  const [selectedId, setSelectedId] = usePluginPaneState<string | null>("selectedId", null);
81
114
  const [sortPreference, setSortPreference] = useState<CatalogSortPreference>(DEFAULT_SORT);
82
115
  const { active: searchFocused, focus: focusSearch, searchProps } = useQueryBarSearch();
83
116
 
117
+ const entries = useRegisteredSeries();
118
+ const catalogRows = useMemo(() => catalogRowsFromEntries(entries), [entries]);
119
+ const filter = normalizeCatalogFilter(savedFilter, catalogRows);
84
120
  const tickerQuery = looksLikeCatalogTickerQuery(searchQuery);
85
121
  const { instruments, loading: universeLoading } = useCatalogUniverse(
86
122
  tickerQuery ? searchQuery : "",
@@ -88,25 +124,20 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
88
124
  const loading = tickerQuery && universeLoading;
89
125
  const emptyCopy = catalogEmptyCopy(loading, searchQuery);
90
126
 
127
+ const listedCrypto = useMemo(
128
+ () => catalogRowsForListedCrypto(catalogRows, instruments),
129
+ [catalogRows, instruments],
130
+ );
91
131
  const rows = useMemo(() => {
92
- const staticRows = listStaticCatalogInventory(instruments);
93
132
  const resolvedRows = tickerQuery
94
133
  ? catalogRowsForResolvedInstruments(
134
+ catalogRows,
95
135
  instruments.filter((instrument) => catalogInstrumentMatchesQuery(instrument, searchQuery)),
96
136
  )
97
137
  : [];
98
- const merged = new Map<string, CatalogSeriesRow>();
99
- for (const entry of [...resolvedRows, ...staticRows]) {
100
- if (!merged.has(entry.id)) merged.set(entry.id, entry);
101
- }
102
- const filtered = filterCatalogRows([...merged.values()], filter, searchQuery);
103
- const direction = sortPreference.direction;
104
- const columnId = sortPreference.columnId;
105
- return [...filtered].sort((left, right) => (
106
- compareSortValues(sortValue(columnId, left), sortValue(columnId, right), direction)
107
- || left.label.localeCompare(right.label)
108
- ));
109
- }, [filter, instruments, searchQuery, sortPreference, tickerQuery]);
138
+ const merged = mergeCatalogRows(catalogRows, [...resolvedRows, ...listedCrypto]);
139
+ return sortRows(filterCatalogRows(merged, filter, searchQuery), sortPreference);
140
+ }, [catalogRows, filter, instruments, listedCrypto, searchQuery, sortPreference, tickerQuery]);
110
141
 
111
142
  useEffect(() => {
112
143
  if (selectedId && rows.some((row) => row.id === selectedId)) return;
@@ -119,12 +150,13 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
119
150
  );
120
151
  const selectedUrl = selectedRow?.url ?? null;
121
152
 
122
- const columns = useMemo(() => buildColumns(width), [width]);
153
+ const columns = useMemo(() => buildColumns(width, filter === "all"), [filter, width]);
123
154
 
124
155
  const chartSelected = useCallback(async (row: CatalogSeriesRow | null) => {
125
156
  if (!row) return;
126
- if (row.needsTicker) {
127
- const option = row.sourceId === "option";
157
+ if (row.input) {
158
+ const option = row.input === "option";
159
+ const crypto = row.input === "crypto";
128
160
  const ticker = await dialog.prompt<string>({
129
161
  closeOnClickOutside: true,
130
162
  content: (context: PromptContext<string>) => (
@@ -133,11 +165,13 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
133
165
  step={{
134
166
  key: "ticker",
135
167
  label: `Chart ${row.label}`,
136
- placeholder: option ? "AAPL 260618C00200000" : "AAPL",
168
+ placeholder: option ? "AAPL 260618C00200000" : crypto ? "BTC-USD" : "AAPL",
137
169
  type: "text",
138
170
  body: [option
139
171
  ? `Enter an option symbol to chart ${row.label}.`
140
- : `Enter a ticker to chart ${row.label}.`],
172
+ : crypto
173
+ ? `Enter a crypto pair to chart ${row.label}.`
174
+ : `Enter a ticker to chart ${row.label}.`],
141
175
  }}
142
176
  />
143
177
  ),
@@ -147,7 +181,7 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
147
181
  createPaneFromTemplate(CHART_COMPOSER_TEMPLATE_ID, { arg: expression });
148
182
  return;
149
183
  }
150
- createPaneFromTemplate(CHART_COMPOSER_TEMPLATE_ID, { arg: row.expression });
184
+ createPaneFromTemplate(CHART_COMPOSER_TEMPLATE_ID, { arg: row.template });
151
185
  }, [createPaneFromTemplate, dialog]);
152
186
 
153
187
  // `/` and `g` are footer hints, which bind their own keys; the table only
@@ -171,10 +205,14 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
171
205
  switch (column.id) {
172
206
  case "series":
173
207
  return { text: row.label, color: colors.textBright };
208
+ case "group":
209
+ return { text: row.group, color: colors.textDim };
210
+ case "unit":
211
+ return { text: row.unit, color: colors.textDim };
212
+ case "frequency":
213
+ return { text: FREQUENCY_LABELS[row.frequency], color: colors.textDim };
174
214
  case "publisher":
175
215
  return { text: row.publisher, color: colors.textMuted };
176
- case "kind":
177
- return { text: row.kind, color: colors.textDim };
178
216
  case "expression":
179
217
  return { text: row.expression, color: colors.text };
180
218
  }
@@ -195,10 +233,10 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
195
233
  });
196
234
 
197
235
  const tabs = useMemo(
198
- () => CATALOG_FILTERS.map((entry) => ({ label: entry.label, value: entry.id })),
199
- [],
236
+ () => catalogTabs(catalogRows).map((entry) => ({ label: entry.label, value: entry.id })),
237
+ [catalogRows],
200
238
  );
201
- const selectFilter = useCallback((value: string) => setFilter(value as CatalogFilterId), [setFilter]);
239
+ const selectFilter = useCallback((value: string) => setFilter(value), [setFilter]);
202
240
  const { strip: tabStrip } = usePaneTabs({
203
241
  tabs,
204
242
  activeValue: filter,
@@ -78,14 +78,15 @@ export function SeriesEditorDialog({ dialogId, resolve, initialSpec }: SeriesEdi
78
78
  while (navigationKeys.length > 0 && [...navigationKeys, ...seriesKeys].join(" · ").length > tuiContentWidth) {
79
79
  navigationKeys.pop();
80
80
  }
81
- const footer = isDesktop
82
- ? seriesKeys.join(" · ") || undefined
83
- : [...navigationKeys, ...seriesKeys].join(" · ");
84
81
 
85
82
  return (
86
83
  <DialogFrame
87
84
  title="Chart Series"
88
- footer={footer}
85
+ footer={[...navigationKeys, ...seriesKeys].join(" · ")}
86
+ // The desktop's fields take the pointer and arrows like any form.
87
+ desktopFooter={selected
88
+ ? { keys: [{ key: "E", label: "source" }, { key: "P", label: "panel" }, { key: "L", label: "log scale" }] }
89
+ : null}
89
90
  >
90
91
  <Box
91
92
  flexDirection="column"
@@ -0,0 +1,40 @@
1
+ import { isMarketFieldId, listTimeSeriesFields } from "../../../time-series/field-catalog";
2
+ import type { SeriesPeriod, TimeSeriesFieldDefinition } from "../../../time-series/types";
3
+ import type { SeriesDefinition, SeriesFrequency } from "../../../series/types";
4
+ import { fieldCategory } from "./series-catalog";
5
+
6
+ /** The short name an expression uses for a field: `price` for OHLCV, else the id's last part. */
7
+ function chartFieldToken(fieldId: string): string {
8
+ if (fieldId === "market.ohlcv") return "price";
9
+ return fieldId.split(".").at(-1) ?? fieldId;
10
+ }
11
+
12
+ function fieldFrequency(period: SeriesPeriod): SeriesFrequency {
13
+ if (period === "auto") return "daily";
14
+ return period === "ttm" ? "quarterly" : period;
15
+ }
16
+
17
+ function fieldSeries(field: TimeSeriesFieldDefinition, input: "ticker" | "option"): SeriesDefinition {
18
+ return {
19
+ id: `${input === "option" ? "option" : "field"}:${field.id}`,
20
+ name: field.label,
21
+ unit: field.unit,
22
+ frequency: fieldFrequency(field.nativeFrequency),
23
+ group: input === "option" ? "Options" : "Securities",
24
+ tags: [fieldCategory(field), field.shortLabel, ...(input === "option" ? ["option"] : [])],
25
+ input,
26
+ expression: `{ticker}:${chartFieldToken(field.id)}`,
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Every ticker field once, asking for the ticker when charted, and the market
32
+ * fields again for option contracts. Typing a ticker in the catalog fills them in.
33
+ */
34
+ export function listFieldSeries(): SeriesDefinition[] {
35
+ const fields = listTimeSeriesFields();
36
+ return [
37
+ ...fields.map((field) => fieldSeries(field, "ticker")),
38
+ ...fields.filter((field) => isMarketFieldId(field.id)).map((field) => fieldSeries(field, "option")),
39
+ ];
40
+ }
@@ -212,11 +212,16 @@ export async function loadChartPaneModel(
212
212
  /**
213
213
  * Price series are bar histories, stale once bars of the coarsest size stop
214
214
  * arriving; fundamentals, valuations and economic series are reported data.
215
+ * A chart of capability series alone (CHOKE's vessel transits) is a dataset,
216
+ * dated by its newest observation and how far behind that is.
215
217
  */
216
- function chartFreshness(series: readonly HeadlessSeries[]): HeadlessPaneFreshness {
218
+ function chartFreshness(series: readonly HeadlessSeries[], spec: ChartSpec): HeadlessPaneFreshness {
217
219
  const order = ["1wk", "1mo"];
218
220
  const resolutions = series.map((entry) => (entry as HeadlessSeries & { historyResolution?: string }).historyResolution);
219
- if (!series.length || resolutions.some((resolution) => !resolution)) return { ...REPORTED_DATA, basis: "reported and published data" };
221
+ const dataset = spec.series.length > 0 && spec.series.every(({ source }) => source.kind === "capability");
222
+ if (!series.length || resolutions.some((resolution) => !resolution)) {
223
+ return { ...REPORTED_DATA, basis: "reported and published data", ...(dataset ? { dataset } : {}) };
224
+ }
220
225
  const coarsest = resolutions.reduce((worst, resolution) => (
221
226
  order.indexOf(resolution!) > order.indexOf(worst!) ? resolution : worst
222
227
  ), resolutions[0]);
@@ -296,7 +301,7 @@ export function chartHeadless(template: keyof typeof paneSchemas): HeadlessPaneD
296
301
  }
297
302
  }
298
303
  model.snapshot.intradayHistories = intradayHistories;
299
- model.freshness = chartFreshness(model.series);
304
+ model.freshness = chartFreshness(model.series, model.spec);
300
305
  const priceDomainFailures = intradayHistories.flatMap(({ symbol, exchange, priceDomainFailure }) =>
301
306
  priceDomainFailure ? [{ symbol, exchange, ...priceDomainFailure }] : []);
302
307
  if (priceDomainFailures.length) {
@@ -13,6 +13,8 @@ import type { ChartSpec } from "../../../time-series/types";
13
13
  import { isPriceOnlyMarketFieldId } from "../../../time-series/field-catalog";
14
14
  import { ChartComposerPane, ChartComposerResearchTab } from "./pane";
15
15
  import { DataCatalogPane } from "./data-catalog-pane";
16
+ import { listFieldSeries } from "./field-series";
17
+ import { registeredSeriesName } from "./series-expression";
16
18
  import {
17
19
  CHART_COMPOSER_TEMPLATE_ID,
18
20
  DATA_CATALOG_PANE_ID,
@@ -104,7 +106,7 @@ function chartTitle(spec: ChartSpec, prefix = "G"): string {
104
106
  ? tickerInstrumentLabel(publicTickerKey(series.source.instrument.symbol, series.source.instrument.exchange), series.source.instrument.instrument)
105
107
  : series.source.kind === "economic"
106
108
  ? `FRED:${series.source.seriesId}`
107
- : series.label?.trim() || series.source.seriesId
109
+ : series.label?.trim() || registeredSeriesName(series.source) || series.source.seriesId
108
110
  ));
109
111
  if (labels.length === 0) return "Custom Chart";
110
112
  const remaining = spec.series.length - labels.length;
@@ -319,7 +321,7 @@ const chartComposerTemplates: PaneTemplateDef[] = [
319
321
  id: DATA_CATALOG_TEMPLATE_ID,
320
322
  paneId: DATA_CATALOG_PANE_ID,
321
323
  label: "Data Catalog",
322
- description: "Browse and search the series Custom Chart already knows: securities, options, crypto, FRED, treasuries, and futures.",
324
+ description: "Browse and search every series a chart can draw: securities, rates, credit, economic data, volatility, sentiment, positioning and your own files.",
323
325
  keywords: [
324
326
  "catalog",
325
327
  "series",
@@ -331,6 +333,9 @@ const chartComposerTemplates: PaneTemplateDef[] = [
331
333
  "crypto",
332
334
  "options",
333
335
  "option",
336
+ "credit",
337
+ "sentiment",
338
+ "positioning",
334
339
  ],
335
340
  shortcut: { prefix: "CAT", argPlaceholder: "query", argKind: "text", argOptional: true },
336
341
  canCreate: () => true,
@@ -424,6 +429,8 @@ function chartShowsOneSecurity(pane: PaneInstanceConfig): boolean {
424
429
  }
425
430
 
426
431
  export const chartComposerModule: PluginModule = {
432
+ // Every ticker field, asking for the ticker when charted.
433
+ series: listFieldSeries(),
427
434
  panes: [{
428
435
  id: CHART_COMPOSER_PANE_ID,
429
436
  name: "Chart",
@@ -7,11 +7,7 @@ import {
7
7
  type ChartSeriesCatalogItem,
8
8
  } from "../../../capabilities";
9
9
  import type { TimeSeriesFieldDefinition } from "../../../time-series/types";
10
- import {
11
- FUTURES_CONTRACTS,
12
- FUTURES_SECTOR_LABELS,
13
- } from "../futures/contracts";
14
- import { TREASURY_MATURITIES } from "../yield-curve/treasury-data";
10
+ import type { SeriesCatalogEntry } from "../../../series/types";
15
11
  import {
16
12
  canonicalExchange,
17
13
  parsePublicTickerKey,
@@ -271,50 +267,61 @@ function matchesAliasQuery(query: string, ...values: string[]): boolean {
271
267
  return tokens.length > 0 && tokens.every((token) => searchable.includes(token));
272
268
  }
273
269
 
274
- function coreAliasSuggestions(query: string): SeriesCatalogSuggestion[] {
275
- const futures = FUTURES_CONTRACTS
276
- .filter((contract) => matchesAliasQuery(
277
- query,
278
- `FUT:${contract.code}`,
279
- contract.code,
280
- contract.name,
281
- `${contract.name} futures`,
282
- contract.sector,
283
- FUTURES_SECTOR_LABELS[contract.sector],
284
- ))
285
- .map((contract): SeriesCatalogSuggestion => ({
286
- id: `${contract.symbol}:market.ohlcv`,
287
- label: `FUT:${contract.code} · ${contract.name}`,
288
- description: `${FUTURES_SECTOR_LABELS[contract.sector]} futures`,
289
- detail: "Futures",
290
- expression: {
291
- kind: "security",
292
- symbol: contract.symbol,
293
- fieldId: "market.ohlcv",
294
- label: contract.name,
295
- },
296
- }));
297
- const treasuries = TREASURY_MATURITIES
298
- .filter((treasury) => matchesAliasQuery(
299
- query,
300
- `UST:${treasury.maturity}`,
301
- treasury.maturity,
302
- treasury.seriesId,
303
- `${treasury.maturity.replace("M", " month").replace("Y", " year")} US Treasury yield`,
304
- ))
305
- .map((treasury): SeriesCatalogSuggestion => ({
306
- id: `fred:${treasury.seriesId}`,
307
- label: `UST:${treasury.maturity} · Treasury Yield`,
308
- description: `U.S. Treasury ${treasury.maturity} yield · FRED ${treasury.seriesId}`,
309
- detail: "Treasury",
310
- expression: {
311
- kind: "economic",
312
- provider: "fred",
313
- seriesId: treasury.seriesId,
314
- label: `${treasury.maturity} Treasury Yield`,
315
- },
316
- }));
317
- return [...futures, ...treasuries];
270
+ function suggestionId(expression: ParsedSeriesExpression): string {
271
+ if (expression.kind === "economic") return `fred:${expression.seriesId}`;
272
+ if (expression.kind === "capability") {
273
+ return chartSeriesSourceKey({ kind: "capability", capabilityId: expression.capabilityId, seriesId: expression.seriesId });
274
+ }
275
+ return `${publicTickerKey(expression.symbol, expression.exchange)}:${expression.fieldId}`;
276
+ }
277
+
278
+ function registeredMatchRank(entry: SeriesCatalogEntry, query: string): number {
279
+ const name = compact(entry.name);
280
+ const needle = compact(query);
281
+ if (name === needle || compact(entry.expression) === needle) return 0;
282
+ if (name.startsWith(needle)) return 1;
283
+ return 2;
284
+ }
285
+
286
+ /**
287
+ * Registered catalog series the query names: by name, expression, group or
288
+ * tags. A series that takes a ticker is filled in with the one the query
289
+ * names, or the chart's own; ticker fields come from the field ranking instead.
290
+ */
291
+ function registeredSeriesSuggestions(
292
+ query: string,
293
+ registered: readonly SeriesCatalogEntry[],
294
+ analysis: SeriesSearchAnalysis,
295
+ defaultInstrument: SeriesCatalogInstrument,
296
+ ): SeriesCatalogSuggestion[] {
297
+ if (!query.trim() || registered.length === 0) return [];
298
+ const instrument = analysis.directInstrument ?? defaultInstrument;
299
+ const tickerQuery = analysis.directInstrument ? analysis.metricQuery : query;
300
+ const hits: Array<{ entry: SeriesCatalogEntry; rank: number; expression: ParsedSeriesExpression }> = [];
301
+ for (const entry of registered) {
302
+ let template = entry.expression;
303
+ let text = query;
304
+ if (entry.input) {
305
+ // Ticker fields are ranked against the security below; options and pairs need their own symbol.
306
+ if (entry.input !== "ticker" || /^\{ticker\}:[A-Za-z]/.test(template) || !tickerQuery.trim()) continue;
307
+ const symbol = publicTickerKey(instrument.symbol, instrument.exchange);
308
+ template = template.replaceAll("{ticker}", template.startsWith("CAP:") ? encodeURIComponent(symbol) : symbol);
309
+ text = tickerQuery;
310
+ }
311
+ if (!matchesAliasQuery(text, entry.name, entry.expression, entry.id, entry.group ?? "", ...(entry.tags ?? []))) continue;
312
+ const parsed = parseSeriesExpression(template);
313
+ if (!parsed) continue;
314
+ const label = entry.input ? `${publicTickerKey(instrument.symbol, instrument.exchange)} · ${entry.name}` : entry.name;
315
+ hits.push({ entry, rank: registeredMatchRank(entry, text), expression: { ...parsed, label } });
316
+ }
317
+ hits.sort((left, right) => left.rank - right.rank || left.entry.name.length - right.entry.name.length);
318
+ return hits.map(({ entry, expression }): SeriesCatalogSuggestion => ({
319
+ id: suggestionId(expression),
320
+ label: expression.kind === "capability" ? expression.label ?? entry.name : `${entry.expression} · ${entry.name}`,
321
+ description: [entry.group, entry.unit, entry.frequency].filter(Boolean).join(" · "),
322
+ detail: entry.group ?? "Series",
323
+ expression,
324
+ }));
318
325
  }
319
326
 
320
327
  export function buildCapabilitySeriesSuggestions(
@@ -345,6 +352,7 @@ export function buildSeriesCatalogSuggestions(
345
352
  defaultInstrument: SeriesCatalogInstrument,
346
353
  searchedInstruments: readonly SeriesCatalogInstrument[] = [],
347
354
  limit = 8,
355
+ registered: readonly SeriesCatalogEntry[] = [],
348
356
  ): SeriesCatalogSuggestion[] {
349
357
  const exact = exactExpressionSuggestion(query.trim());
350
358
  const analysis = analyzeSeriesSearchQuery(query);
@@ -362,7 +370,7 @@ export function buildSeriesCatalogSuggestions(
362
370
  .sort((left, right) => right.score - left.score || left.field.label.localeCompare(right.field.label));
363
371
 
364
372
  const suggestions: SeriesCatalogSuggestion[] = exact ? [exact] : [];
365
- for (const suggestion of coreAliasSuggestions(query)) {
373
+ for (const suggestion of registeredSeriesSuggestions(query, registered, analysis, defaultInstrument)) {
366
374
  if (!suggestions.some((entry) => entry.id === suggestion.id)) suggestions.push(suggestion);
367
375
  }
368
376
  const fieldLimit = instruments.length > 1 && !analysis.metricQuery ? 1 : rankedFields.length;
@@ -15,7 +15,8 @@ import {
15
15
  isValidChartCapabilityId,
16
16
  isValidChartSeriesId,
17
17
  } from "../../../capabilities/chart-series";
18
- import { FUTURES_CONTRACTS } from "../futures/contracts";
18
+ import { futuresContractByCode } from "../../../market-data/futures-board";
19
+ import { getSharedRegistry } from "../../registry";
19
20
  import { TREASURY_MATURITIES } from "../yield-curve/treasury-data";
20
21
 
21
22
  export const CHART_FIELD_IDS = {
@@ -100,9 +101,9 @@ export function parseSeriesExpression(value: string): ParsedSeriesExpression | n
100
101
  if (separator < 0) return null;
101
102
  const capabilityId = trimmed.slice(4, separator);
102
103
  const seriesId = trimmed.slice(separator + 1);
103
- return isValidChartCapabilityId(capabilityId) && isValidChartSeriesId(seriesId)
104
- ? { kind: "capability", capabilityId, seriesId }
105
- : null;
104
+ if (!isValidChartCapabilityId(capabilityId) || !isValidChartSeriesId(seriesId)) return null;
105
+ const label = registeredSeriesName({ capabilityId, seriesId });
106
+ return { kind: "capability", capabilityId, seriesId, ...(label ? { label } : {}) };
106
107
  }
107
108
  if (parts[0]?.trim().toUpperCase() === "GEO") {
108
109
  const seriesId = trimmed.slice(trimmed.indexOf(":") + 1).trim();
@@ -112,13 +113,13 @@ export function parseSeriesExpression(value: string): ParsedSeriesExpression | n
112
113
  }
113
114
  if (parts[0]?.trim().toUpperCase() === "FRED") {
114
115
  const seriesId = parts.length === 2 ? parts[1]?.trim().toUpperCase() ?? "" : "";
115
- return /^[A-Z0-9._-]{1,80}$/.test(seriesId)
116
- ? { kind: "economic", provider: "fred", seriesId }
117
- : null;
116
+ if (!/^[A-Z0-9._-]{1,80}$/.test(seriesId)) return null;
117
+ // The catalog's name for a listed series, so the legend says what the catalog said.
118
+ const label = getSharedRegistry()?.series?.findByExpression(`FRED:${seriesId}`)?.definition.name;
119
+ return { kind: "economic", provider: "fred", seriesId, ...(label ? { label } : {}) };
118
120
  }
119
121
  if (parts.length === 2 && parts[0]?.trim().toUpperCase() === "FUT") {
120
- const code = parts[1]?.trim().toUpperCase();
121
- const contract = FUTURES_CONTRACTS.find((entry) => entry.code === code);
122
+ const contract = futuresContractByCode(parts[1]);
122
123
  return contract
123
124
  ? { kind: "security", symbol: contract.symbol, fieldId: CHART_FIELD_IDS.price, label: contract.name }
124
125
  : null;
@@ -189,10 +190,17 @@ export function formatSeriesExpression(series: ChartSeriesSpec): string {
189
190
  return `${publicTickerKey(series.source.instrument.symbol, series.source.instrument.exchange)}:${series.source.fieldId}`;
190
191
  }
191
192
 
193
+ /** A registered catalog series' name, with the ticker it was charted for. */
194
+ export function registeredSeriesName(source: { capabilityId: string; seriesId: string }): string | null {
195
+ const found = getSharedRegistry()?.series?.findLoaded(source.capabilityId, source.seriesId);
196
+ if (!found) return null;
197
+ return found.ticker ? `${found.ticker} ${found.series.definition.name}` : found.series.definition.name;
198
+ }
199
+
192
200
  export function chartSeriesLabel(series: ChartSeriesSpec): string {
193
201
  if (series.label?.trim()) return series.label.trim();
194
202
  if (series.source.kind === "economic") return `FRED ${series.source.seriesId}`;
195
- if (series.source.kind === "capability") return series.source.seriesId;
203
+ if (series.source.kind === "capability") return registeredSeriesName(series.source) ?? series.source.seriesId;
196
204
  const generic = getTimeSeriesField(series.source.fieldId)?.unitGroup === "price"
197
205
  ? futuresGenericListing(series.source.instrument.symbol, series.source.instrument.exchange) : null;
198
206
  if (generic) return futuresGenericCaption(generic);