gloomberb 0.16.0 → 0.16.2

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 (691) hide show
  1. package/README.md +2 -1
  2. package/package.json +2 -1
  3. package/src/api-client/beneficial-owners.ts +92 -0
  4. package/src/api-client/data.ts +44 -11
  5. package/src/api-client/errors.ts +12 -0
  6. package/src/api-client/geo.ts +363 -0
  7. package/src/api-client/index.ts +5 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/members.ts +26 -0
  10. package/src/api-client/paths.ts +30 -1
  11. package/src/api-client/perps.ts +41 -0
  12. package/src/api-client/request.ts +5 -2
  13. package/src/api-client/types.ts +9 -1
  14. package/src/app/global-shortcuts.ts +14 -6
  15. package/src/app/keybindings/actions.ts +1 -1
  16. package/src/app/runtime/update.ts +38 -2
  17. package/src/app.tsx +10 -6
  18. package/src/brokers/account-cache.ts +24 -0
  19. package/src/cli/commands/command-utils.ts +8 -0
  20. package/src/cli/commands/crypto-hints.ts +75 -0
  21. package/src/cli/commands/market.ts +414 -106
  22. package/src/cli/commands/overview.ts +77 -32
  23. package/src/cli/commands/ticker.ts +101 -43
  24. package/src/cli/desktop-pane-shot.ts +34 -4
  25. package/src/cli/freshness.ts +61 -0
  26. package/src/cli/help.ts +1 -0
  27. package/src/cli/helpers.ts +4 -8
  28. package/src/cli/index.ts +12 -2
  29. package/src/cli/listing-arg.ts +321 -0
  30. package/src/cli/pane-functions/access-gate.ts +42 -0
  31. package/src/cli/pane-functions/catalog.ts +28 -1
  32. package/src/cli/pane-functions/data.ts +3 -1
  33. package/src/cli/pane-functions/dom.ts +20 -2
  34. package/src/cli/pane-functions/freshness.ts +400 -0
  35. package/src/cli/pane-functions/function-help.ts +36 -22
  36. package/src/cli/pane-functions/headless.ts +39 -11
  37. package/src/cli/pane-functions/index.ts +15 -4
  38. package/src/cli/pane-functions/options.ts +3 -0
  39. package/src/cli/pane-functions/report.ts +4 -0
  40. package/src/cli/pane-functions/resolver.ts +35 -7
  41. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  42. package/src/cli/pane-functions/screenshot.ts +7 -3
  43. package/src/cli/result.ts +41 -27
  44. package/src/cli/ticker-resolution.ts +7 -5
  45. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  46. package/src/components/chart/composite/drawing-store.ts +59 -0
  47. package/src/components/chart/composite/legend.tsx +319 -0
  48. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  49. package/src/components/chart/composite/panel-gestures.ts +59 -0
  50. package/src/components/chart/composite/panel-labels.ts +107 -0
  51. package/src/components/chart/composite/panel-surface.tsx +876 -0
  52. package/src/components/chart/composite/tool-catalog.ts +98 -0
  53. package/src/components/chart/composite/toolbar.tsx +186 -0
  54. package/src/components/chart/composite/tools.ts +8 -0
  55. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  56. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  57. package/src/components/command-bar/commands/collection.ts +5 -1
  58. package/src/components/command-bar/list/model.ts +5 -0
  59. package/src/components/command-bar/list/view.tsx +16 -3
  60. package/src/components/command-bar/pane-templates/workflow.ts +1 -0
  61. package/src/components/command-bar/routes/root/command-items.ts +9 -2
  62. package/src/components/command-bar/routes/root/plugin-install.ts +2 -2
  63. package/src/components/command-bar/routes/root/provider-search.ts +19 -5
  64. package/src/components/command-bar/routes/root/runtime.ts +14 -5
  65. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  66. package/src/components/command-bar/routes/ticker-search/results.ts +31 -5
  67. package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
  68. package/src/components/command-bar/routing/actions.ts +2 -0
  69. package/src/components/command-bar/selection-runtime.ts +38 -0
  70. package/src/components/command-bar/surface/index.tsx +7 -2
  71. package/src/components/command-bar/workflow/ops.ts +1 -1
  72. package/src/components/command-bar/workflow/tickers.ts +6 -0
  73. package/src/components/data-table/view.tsx +29 -10
  74. package/src/components/feedback-dialog.tsx +2 -1
  75. package/src/components/form-modal/field-row.tsx +2 -2
  76. package/src/components/index.ts +2 -2
  77. package/src/components/layout/detached-pane-shell.tsx +6 -3
  78. package/src/components/layout/floating-pane.tsx +6 -0
  79. package/src/components/layout/header.tsx +24 -7
  80. package/src/components/layout/missing-pane.tsx +2 -2
  81. package/src/components/layout/pane/content.tsx +23 -10
  82. package/src/components/layout/pane/error-boundary.tsx +103 -0
  83. package/src/components/layout/pane/footer/registration.tsx +68 -23
  84. package/src/components/layout/pane/header.tsx +61 -28
  85. package/src/components/layout/pane/index.tsx +6 -0
  86. package/src/components/layout/pane/title.ts +31 -7
  87. package/src/components/layout/shell/drag/index.ts +6 -5
  88. package/src/components/layout/shell/drag/runtime.ts +3 -0
  89. package/src/components/layout/shell/index.tsx +6 -0
  90. package/src/components/layout/shell/menu.ts +2 -1
  91. package/src/components/layout/shell/pane/actions.ts +2 -1
  92. package/src/components/layout/shell/pane/layers.tsx +29 -10
  93. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -3
  94. package/src/components/layout/shell/ticker-link-menu.ts +23 -9
  95. package/src/components/metric-treemap/heat-surface.tsx +745 -0
  96. package/src/components/metric-treemap/heat-tiles.ts +228 -0
  97. package/src/components/metric-treemap/index.tsx +2 -0
  98. package/src/components/metric-treemap/layout.ts +8 -0
  99. package/src/components/metric-treemap/scene.ts +432 -0
  100. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  101. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  102. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  103. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  104. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  105. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -0
  106. package/src/components/ticker/list-table-view.tsx +13 -1
  107. package/src/components/toggle-list.tsx +38 -12
  108. package/src/components/ui/country-flag-art.tsx +449 -0
  109. package/src/components/ui/country-flag.tsx +41 -0
  110. package/src/components/ui/data-table/types.ts +13 -0
  111. package/src/components/ui/fields.tsx +8 -0
  112. package/src/components/ui/icon.tsx +2 -0
  113. package/src/components/ui/index.ts +4 -0
  114. package/src/components/ui/multi-select/dialog.tsx +108 -22
  115. package/src/components/ui/range-track.tsx +53 -0
  116. package/src/components/ui/status.tsx +8 -2
  117. package/src/components/ui/tabs.tsx +11 -4
  118. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  119. package/src/core/state/app/types.ts +10 -1
  120. package/src/data/config/store/normalize.ts +17 -1
  121. package/src/i18n/es.ts +24 -4
  122. package/src/i18n/ja.ts +24 -4
  123. package/src/i18n/ko.ts +24 -4
  124. package/src/i18n/zh-cn.ts +24 -4
  125. package/src/i18n/zh-tw.ts +24 -4
  126. package/src/layout/ticker-navigation.ts +28 -2
  127. package/src/market-data/coordinator/chart.ts +1 -1
  128. package/src/market-data/coordinator/quotes.ts +23 -4
  129. package/src/market-data/fx-closes.ts +72 -0
  130. package/src/market-data/market/freshness.ts +78 -6
  131. package/src/market-data/market/session-close-note.ts +57 -0
  132. package/src/market-data/market/status.ts +151 -0
  133. package/src/market-data/published-apac-sessions.ts +66 -0
  134. package/src/market-data/quotes/contributions.ts +8 -0
  135. package/src/market-data/quotes/freshness.ts +36 -0
  136. package/src/market-data/quotes/resolution.ts +24 -8
  137. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  138. package/src/market-data/quotes/time.ts +16 -0
  139. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  140. package/src/plugins/builtin/alerts/cli.ts +10 -5
  141. package/src/plugins/builtin/alerts/index.tsx +1 -0
  142. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  143. package/src/plugins/builtin/analytics/risk-client.ts +330 -79
  144. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  145. package/src/plugins/builtin/analytics/risk-headless.ts +61 -49
  146. package/src/plugins/builtin/analytics/risk-math.ts +33 -13
  147. package/src/plugins/builtin/analytics/risk-model.ts +282 -64
  148. package/src/plugins/builtin/analytics/risk-pane.tsx +62 -30
  149. package/src/plugins/builtin/analytics/risk-test-data.ts +206 -0
  150. package/src/plugins/builtin/attention/headless.ts +6 -4
  151. package/src/plugins/builtin/attention/index.tsx +1 -1
  152. package/src/plugins/builtin/attention/pane.tsx +1 -1
  153. package/src/plugins/builtin/awards/headless.ts +1 -0
  154. package/src/plugins/builtin/awards/pane.tsx +1 -1
  155. package/src/plugins/builtin/backtest/headless.ts +1 -0
  156. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  157. package/src/plugins/builtin/buildout/cells.tsx +15 -12
  158. package/src/plugins/builtin/buildout/detail/company.tsx +3 -3
  159. package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
  160. package/src/plugins/builtin/buildout/detail/intel.tsx +6 -6
  161. package/src/plugins/builtin/buildout/detail/site.tsx +4 -7
  162. package/src/plugins/builtin/buildout/detail/ui.tsx +0 -19
  163. package/src/plugins/builtin/buildout/index.tsx +1 -0
  164. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  165. package/src/plugins/builtin/catalysts/index.tsx +2 -2
  166. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  167. package/src/plugins/builtin/cds/headless.ts +2 -0
  168. package/src/plugins/builtin/cds/index.tsx +1 -0
  169. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  170. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  171. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  172. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  173. package/src/plugins/builtin/chat/channels.ts +19 -3
  174. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  175. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  176. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  177. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  178. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  179. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  180. package/src/plugins/builtin/chat/index.tsx +1 -0
  181. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  182. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  183. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  184. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  185. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  186. package/src/plugins/builtin/chat/message/types.ts +14 -2
  187. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  188. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  189. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  190. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  191. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  192. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  193. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  194. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  195. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  196. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  197. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  198. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  199. package/src/plugins/builtin/correlation/compute.ts +59 -16
  200. package/src/plugins/builtin/correlation/geo.ts +34 -0
  201. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  202. package/src/plugins/builtin/correlation/headless.ts +42 -8
  203. package/src/plugins/builtin/correlation/history.ts +2 -0
  204. package/src/plugins/builtin/correlation/index.tsx +68 -14
  205. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  206. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  207. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  208. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  209. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  210. package/src/plugins/builtin/correlation/settings.ts +1 -1
  211. package/src/plugins/builtin/cot/headless.ts +6 -3
  212. package/src/plugins/builtin/cot/index.tsx +3 -3
  213. package/src/plugins/builtin/cot/model.ts +36 -3
  214. package/src/plugins/builtin/cpi/headless.ts +4 -0
  215. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  216. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  217. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  218. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  219. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  220. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  221. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  222. package/src/plugins/builtin/debt-maturities/wall-bar.tsx +14 -41
  223. package/src/plugins/builtin/dividend-yield/client.ts +4 -2
  224. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  225. package/src/plugins/builtin/doe/headless.ts +7 -0
  226. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  227. package/src/plugins/builtin/earnings/client.ts +2 -2
  228. package/src/plugins/builtin/earnings/headless.ts +5 -0
  229. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  230. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  231. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  232. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  233. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  234. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  235. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  236. package/src/plugins/builtin/econ/index.tsx +1 -0
  237. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  238. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  239. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  240. package/src/plugins/builtin/executives/index.tsx +1 -0
  241. package/src/plugins/builtin/exposure/headless.ts +3 -1
  242. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  243. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  244. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  245. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  246. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  247. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  248. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  249. package/src/plugins/builtin/fx-matrix/direction.ts +81 -0
  250. package/src/plugins/builtin/fx-matrix/index.tsx +71 -33
  251. package/src/plugins/builtin/fx-matrix/live-legs.ts +17 -0
  252. package/src/plugins/builtin/fx-matrix/pairs.ts +68 -14
  253. package/src/plugins/builtin/fx-matrix/settings.ts +62 -0
  254. package/src/plugins/builtin/gpu/headless.ts +7 -3
  255. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  256. package/src/plugins/builtin/gpu/model.ts +27 -1
  257. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  258. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  259. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  260. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  261. package/src/plugins/builtin/holders/headless.ts +139 -5
  262. package/src/plugins/builtin/holders/index.tsx +10 -3
  263. package/src/plugins/builtin/holders/pane.tsx +20 -3
  264. package/src/plugins/builtin/holders/report-header.ts +95 -0
  265. package/src/plugins/builtin/holders/table-model.ts +20 -5
  266. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  267. package/src/plugins/builtin/holders/types.ts +2 -1
  268. package/src/plugins/builtin/insider/headless.ts +2 -0
  269. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  270. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  271. package/src/plugins/builtin/jobs/headless.ts +1 -0
  272. package/src/plugins/builtin/jobs/index.tsx +1 -0
  273. package/src/plugins/builtin/jobs/share-bars.tsx +5 -28
  274. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  275. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  276. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  277. package/src/plugins/builtin/market-heatmap/data.ts +30 -2
  278. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  279. package/src/plugins/builtin/market-heatmap/index.tsx +245 -81
  280. package/src/plugins/builtin/market-heatmap/live.ts +88 -0
  281. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  282. package/src/plugins/builtin/market-heatmap/portfolio.ts +50 -11
  283. package/src/plugins/builtin/market-movers/client.ts +3 -2
  284. package/src/plugins/builtin/market-movers/headless.ts +10 -1
  285. package/src/plugins/builtin/market-movers/screener.ts +18 -5
  286. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  287. package/src/plugins/builtin/members/client.ts +53 -0
  288. package/src/plugins/builtin/members/headless.ts +35 -0
  289. package/src/plugins/builtin/members/index.tsx +20 -0
  290. package/src/plugins/builtin/members/model.ts +68 -0
  291. package/src/plugins/builtin/members/pane.tsx +175 -0
  292. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  293. package/src/plugins/builtin/mna/headless.ts +1 -0
  294. package/src/plugins/builtin/mna/index.tsx +2 -1
  295. package/src/plugins/builtin/mna/pane.tsx +5 -2
  296. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  297. package/src/plugins/builtin/news/headless.ts +2 -0
  298. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  299. package/src/plugins/builtin/notes/cli.ts +14 -6
  300. package/src/plugins/builtin/notes/index.tsx +1 -0
  301. package/src/plugins/builtin/openfda/index.tsx +1 -0
  302. package/src/plugins/builtin/options/index.tsx +2 -1
  303. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  304. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  305. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  306. package/src/plugins/builtin/pe-band/client.ts +74 -2
  307. package/src/plugins/builtin/pe-band/headless.ts +26 -8
  308. package/src/plugins/builtin/pe-band/model.ts +102 -22
  309. package/src/plugins/builtin/pe-band/pane.tsx +34 -16
  310. package/src/plugins/builtin/pe-band/report-dates.ts +78 -0
  311. package/src/plugins/builtin/perps/client.ts +66 -5
  312. package/src/plugins/builtin/perps/equity-identity.ts +16 -0
  313. package/src/plugins/builtin/perps/equity-row.tsx +6 -4
  314. package/src/plugins/builtin/perps/headless.ts +144 -16
  315. package/src/plugins/builtin/perps/index.tsx +6 -6
  316. package/src/plugins/builtin/perps/model.ts +189 -12
  317. package/src/plugins/builtin/perps/pane.tsx +248 -47
  318. package/src/plugins/builtin/plugin-marketplace/activation.ts +19 -0
  319. package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -2
  320. package/src/plugins/builtin/plugin-marketplace/store.ts +2 -0
  321. package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
  322. package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
  323. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  324. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  325. package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
  326. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  327. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  328. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  329. package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
  330. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  331. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  332. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  333. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  334. package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
  335. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +43 -2
  336. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +48 -5
  337. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  338. package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
  339. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  340. package/src/plugins/builtin/power/headless.ts +3 -1
  341. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  342. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  343. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  344. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  345. package/src/plugins/builtin/research/events-headless.ts +2 -0
  346. package/src/plugins/builtin/research/headless.ts +2 -0
  347. package/src/plugins/builtin/research/index.tsx +1 -0
  348. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  349. package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
  350. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  351. package/src/plugins/builtin/research-search/index.tsx +1 -0
  352. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  353. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  354. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  355. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  356. package/src/plugins/builtin/scanner/headless.ts +14 -0
  357. package/src/plugins/builtin/scanner/hilo-bars.tsx +12 -70
  358. package/src/plugins/builtin/scanner/hilo-model.ts +0 -18
  359. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  360. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  361. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  362. package/src/plugins/builtin/sec/forms.ts +12 -0
  363. package/src/plugins/builtin/sec/headless.ts +2 -0
  364. package/src/plugins/builtin/sectors/client.ts +1 -0
  365. package/src/plugins/builtin/sectors/headless.ts +9 -1
  366. package/src/plugins/builtin/sectors/move-bar.tsx +10 -32
  367. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  368. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  369. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  370. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  371. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  372. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  373. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  374. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  375. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  376. package/src/plugins/builtin/social-mentions/index.tsx +1 -1
  377. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  378. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  379. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  380. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  381. package/src/plugins/builtin/themes/headless.ts +3 -0
  382. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  383. package/src/plugins/builtin/thirteenf/index.tsx +2 -1
  384. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  385. package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
  386. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  387. package/src/plugins/builtin/ticker-detail/overview/components.tsx +5 -60
  388. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
  389. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +1 -1
  390. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
  391. package/src/plugins/builtin/ticker-detail/pane.tsx +1 -1
  392. package/src/plugins/builtin/ticker-detail/quote-footer.ts +7 -1
  393. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +20 -4
  394. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -2
  395. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  396. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  397. package/src/plugins/builtin/vol-surface/index.tsx +1 -1
  398. package/src/plugins/builtin/volatility/headless.ts +6 -1
  399. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  400. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
  401. package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
  402. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  403. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  404. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  405. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  406. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  407. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  408. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  409. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
  410. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  411. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  412. package/src/plugins/builtin/world-venue-map/index.ts +67 -4
  413. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
  414. package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
  415. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  416. package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
  417. package/src/plugins/builtin/world-venue-map/model.ts +7 -4
  418. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  524. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  525. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  526. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  527. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  528. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  529. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  530. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  531. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  532. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  533. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  534. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  535. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  536. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  537. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  538. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  539. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  540. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  541. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  542. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  543. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  544. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  545. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  546. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  547. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  548. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  549. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  550. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  551. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  552. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  553. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  554. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  555. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  556. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  557. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  558. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  559. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  560. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  561. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  562. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  563. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  564. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  565. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  566. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  567. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  568. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  569. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  570. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  571. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  572. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  573. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  574. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  575. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  576. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  577. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  578. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  579. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  580. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  581. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  582. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  583. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  584. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  585. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  586. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  587. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  588. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  589. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  590. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  591. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  592. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  593. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  594. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  595. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  596. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  597. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  598. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  599. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  600. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  601. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  602. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  603. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  604. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  605. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  606. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  607. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  608. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  609. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  610. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  611. package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
  612. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  613. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  614. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  615. package/src/plugins/catalog-browser.ts +2 -0
  616. package/src/plugins/catalog-manifest.ts +1 -0
  617. package/src/plugins/catalog-ui.ts +3 -1
  618. package/src/plugins/catalog.ts +1 -1
  619. package/src/plugins/host-link.ts +33 -1
  620. package/src/plugins/installer.ts +48 -12
  621. package/src/plugins/loader.ts +30 -3
  622. package/src/plugins/manager-node.ts +15 -5
  623. package/src/plugins/registry/index.ts +1 -1
  624. package/src/plugins/registry/pane-settings.ts +26 -7
  625. package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
  626. package/src/renderers/dom/build-assets.ts +81 -3
  627. package/src/renderers/dom/data-table/row.tsx +52 -16
  628. package/src/renderers/dom/desktop/controls.tsx +7 -3
  629. package/src/renderers/dom/desktop/icons.tsx +1 -0
  630. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  631. package/src/renderers/dom/desktop/popover.tsx +73 -14
  632. package/src/renderers/dom/host/box.tsx +69 -26
  633. package/src/renderers/dom/host/input.tsx +14 -3
  634. package/src/renderers/dom/host/tabs.tsx +37 -1
  635. package/src/renderers/dom/styles.css +41 -7
  636. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +11 -6
  637. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
  638. package/src/renderers/electrobun/bun/desktop/update.ts +181 -87
  639. package/src/renderers/electrobun/bun/index.ts +73 -6
  640. package/src/renderers/electrobun/bun/window/remembered-frame.ts +122 -0
  641. package/src/renderers/electrobun/shared/protocol.ts +3 -0
  642. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  643. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -1
  644. package/src/renderers/electrobun/view/main.tsx +7 -1
  645. package/src/renderers/electrobun/view/renderer-window-error.ts +18 -0
  646. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  647. package/src/renderers/electrobun/view/update-host.ts +45 -21
  648. package/src/renderers/opentui/host.tsx +5 -0
  649. package/src/sources/gloomberb-cloud/index.ts +25 -4
  650. package/src/sources/gloomberb-cloud/normalizers.ts +36 -5
  651. package/src/sources/provider-router/cached-routes.ts +4 -1
  652. package/src/sources/provider-router/financials.ts +11 -8
  653. package/src/sources/provider-router/history.ts +15 -10
  654. package/src/sources/sec-registrant.ts +75 -0
  655. package/src/state/app/context/index.tsx +24 -8
  656. package/src/state/hooks/quote-streaming.ts +41 -26
  657. package/src/sync/core-contributors.ts +4 -0
  658. package/src/telemetry/benign-window-error.ts +7 -0
  659. package/src/telemetry/crash-reports-dom.ts +2 -0
  660. package/src/telemetry/crash-reports.ts +4 -1
  661. package/src/test-support/cli-context.ts +10 -2
  662. package/src/test-support/daily-nav.ts +25 -0
  663. package/src/theme/heat-colors.ts +357 -2
  664. package/src/tickers/instrument-kind.ts +34 -7
  665. package/src/tickers/search/asset-classes.ts +24 -9
  666. package/src/tickers/search/index.ts +44 -11
  667. package/src/tickers/search/ranking.ts +23 -3
  668. package/src/time-series/resolve.ts +1 -1
  669. package/src/time-series/use-chart-resolution.ts +1 -1
  670. package/src/types/context-menu.ts +6 -0
  671. package/src/types/data-provider.ts +2 -0
  672. package/src/types/financials.ts +5 -0
  673. package/src/types/headless.ts +79 -2
  674. package/src/types/plugin.ts +38 -6
  675. package/src/types/ticker.ts +15 -0
  676. package/src/ui/context-menu.tsx +1 -0
  677. package/src/ui/host.tsx +16 -0
  678. package/src/updater/index.ts +38 -13
  679. package/src/utils/async-deadline.ts +21 -0
  680. package/src/utils/cli-output.ts +5 -1
  681. package/src/utils/crypto-pair.ts +41 -0
  682. package/src/utils/currency-units.ts +14 -0
  683. package/src/utils/depositary-receipt.ts +26 -0
  684. package/src/utils/exchanges.ts +72 -0
  685. package/src/utils/fire-and-forget.ts +24 -0
  686. package/src/utils/format.ts +13 -0
  687. package/src/utils/price-earnings.ts +70 -3
  688. package/src/utils/price-history.ts +58 -13
  689. package/src/utils/rpc-timeout-error.ts +27 -0
  690. package/src/utils/sec.ts +13 -1
  691. package/src/utils/utc-time.ts +79 -0
@@ -1,5 +1,5 @@
1
1
  import type { AppConfig } from "../../../types/config";
2
- import type { Portfolio, TickerPosition, TickerRecord, Watchlist } from "../../../types/ticker";
2
+ import type { Portfolio, PortfolioCash, TickerPosition, TickerRecord, Watchlist } from "../../../types/ticker";
3
3
  import { resolveCurrencyUnit } from "../../../utils/currency-units";
4
4
  import { slugifyName } from "../../../utils/slugify";
5
5
  import { parseCollectionRef } from "../cloud/team/collections";
@@ -149,6 +149,60 @@ export function adoptHeldPortfolioCurrencies(config: AppConfig, tickers: Iterabl
149
149
  return next;
150
150
  }
151
151
 
152
+ function updatePortfolio(config: AppConfig, portfolioId: string, update: (portfolio: Portfolio) => Portfolio): AppConfig {
153
+ if (!config.portfolios.some((portfolio) => portfolio.id === portfolioId)) throw new Error("Portfolio not found.");
154
+ return {
155
+ ...config,
156
+ portfolios: config.portfolios.map((portfolio) => (portfolio.id === portfolioId ? update(portfolio) : portfolio)),
157
+ };
158
+ }
159
+
160
+ /** Records the cash held beside a portfolio's positions, replacing any earlier entry. */
161
+ export function setPortfolioCash(config: AppConfig, portfolioId: string, cash: PortfolioCash): AppConfig {
162
+ const currency = cash.currency.trim().toUpperCase();
163
+ if (!Number.isFinite(cash.amount)) throw new Error("Cash amount must be a valid number.");
164
+ if (!/^[A-Z]{3}$/.test(currency)) throw new Error(`"${cash.currency}" is not a currency code such as USD or EUR.`);
165
+ return updatePortfolio(config, portfolioId, (portfolio) => ({ ...portfolio, cash: { amount: cash.amount, currency } }));
166
+ }
167
+
168
+ export function clearPortfolioCash(config: AppConfig, portfolioId: string): { config: AppConfig; changed: boolean } {
169
+ const portfolio = config.portfolios.find((entry) => entry.id === portfolioId);
170
+ if (!portfolio?.cash) return { config, changed: false };
171
+ return {
172
+ config: updatePortfolio(config, portfolioId, ({ cash: _cash, ...rest }) => rest),
173
+ changed: true,
174
+ };
175
+ }
176
+
177
+ /** Sets one target weight, in percent, keyed by ticker symbol (`CASH` for the cash line). */
178
+ export function setPortfolioTargetWeight(config: AppConfig, portfolioId: string, symbol: string, weight: number): AppConfig {
179
+ if (!Number.isFinite(weight) || weight < 0 || weight > 100) throw new Error("Target weight must be between 0% and 100%.");
180
+ if (!symbol.trim()) throw new Error("Ticker symbol is required.");
181
+ return updatePortfolio(config, portfolioId, (portfolio) => ({
182
+ ...portfolio,
183
+ targetWeights: { ...portfolio.targetWeights, [symbol]: weight },
184
+ }));
185
+ }
186
+
187
+ /** Removes one symbol's target, or every target when no symbol is given. */
188
+ export function clearPortfolioTargetWeights(
189
+ config: AppConfig,
190
+ portfolioId: string,
191
+ symbol?: string,
192
+ ): { config: AppConfig; removed: string[] } {
193
+ const portfolio = config.portfolios.find((entry) => entry.id === portfolioId);
194
+ const current = portfolio?.targetWeights ?? {};
195
+ const removed = symbol == null ? Object.keys(current) : Object.keys(current).filter((key) => key === symbol);
196
+ if (removed.length === 0) return { config, removed };
197
+ const remaining = Object.fromEntries(Object.entries(current).filter(([key]) => !removed.includes(key)));
198
+ return {
199
+ config: updatePortfolio(config, portfolioId, ({ targetWeights: _targets, ...rest }) => (
200
+ Object.keys(remaining).length > 0 ? { ...rest, targetWeights: remaining } : rest
201
+ )),
202
+ removed,
203
+ };
204
+ }
205
+
152
206
  export function createManualPortfolio(
153
207
  config: AppConfig,
154
208
  name: string,
@@ -34,6 +34,9 @@ const QUOTE_SORT_COLUMN_IDS = new Set([
34
34
  "ext_hours",
35
35
  "mkt_value",
36
36
  "weight",
37
+ "drift",
38
+ "trade",
39
+ "trade_value",
37
40
  "day_pnl",
38
41
  "pnl",
39
42
  "pnl_pct",
@@ -153,9 +156,12 @@ export function buildTrackedCurrencies(
153
156
  financialsMap: Map<string, TickerFinancials>,
154
157
  accountState: ResolvedPortfolioAccountState | null,
155
158
  baseCurrency: string,
159
+ /** The currency of cash entered by hand. */
160
+ cashCurrency?: string,
156
161
  ): string[] {
157
162
  const currencies = new Set<string>([baseCurrency]);
158
163
  if (accountState?.account.currency) currencies.add(accountState.account.currency);
164
+ if (cashCurrency) currencies.add(cashCurrency);
159
165
 
160
166
  for (const ticker of tickers) {
161
167
  if (ticker.metadata.currency) {
@@ -89,6 +89,16 @@ import { useThrottledMemo } from "../use-throttled-memo";
89
89
  import { useColumnClock } from "../use-column-clock";
90
90
  import { liveMarketCapitalization } from "../live-valuation";
91
91
  import { hasUnknownOptionMultiplier } from "../position-metrics";
92
+ import {
93
+ allocationTotal,
94
+ buildPortfolioAllocation,
95
+ CASH_SYMBOL,
96
+ hasTargetWeights,
97
+ resolvePortfolioCash,
98
+ } from "../allocation";
99
+
100
+ /** Columns that need the portfolio's total. */
101
+ const ALLOCATION_COLUMN_IDS = new Set(["weight", "drift", "trade", "trade_value"]);
92
102
 
93
103
  // Rows follow every tick. Totals walk the whole collection, so the footer
94
104
  // coalesces to about four updates a second and the weight denominator to one.
@@ -163,9 +173,10 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
163
173
 
164
174
  const accountStateInput = useMemo(() => ({ brokerAccounts, config }), [brokerAccounts, config]);
165
175
  const { accountState, accountsError } = usePortfolioAccountState(currentPortfolio, accountStateInput);
176
+ const portfolioTargets = currentPortfolio?.targetWeights;
166
177
  const columns = useMemo(
167
- () => resolveVisibleColumns(paneSettings.columnIds, isPortfolioTab),
168
- [isPortfolioTab, paneSettings.columnIds],
178
+ () => resolveVisibleColumns(paneSettings.columnIds, isPortfolioTab, { targetWeights: hasTargetWeights(currentPortfolio) }),
179
+ [currentPortfolio, isPortfolioTab, paneSettings.columnIds],
169
180
  );
170
181
  const supplementalData = usePortfolioSupplementalData(tickers, columns, appActive);
171
182
  const visibleWarmupRequirements = useMemo(
@@ -178,19 +189,32 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
178
189
  () => resolvePortfolioTotalsCurrency(currentPortfolio, config.baseCurrency),
179
190
  [config.baseCurrency, currentPortfolio],
180
191
  );
192
+ // The broker account's cash when it reports one, else the cash entered by hand.
193
+ const cashLine = useMemo(
194
+ () => isPortfolioTab ? resolvePortfolioCash(currentPortfolio, accountState?.account) : null,
195
+ [accountState, currentPortfolio, isPortfolioTab],
196
+ );
181
197
  const trackedCurrencies = useMemo(
182
- () => buildTrackedCurrencies(tickers, financialsMap, accountState, totalsCurrency),
183
- [accountState, financialsMap, tickers, totalsCurrency],
198
+ () => buildTrackedCurrencies(tickers, financialsMap, accountState, totalsCurrency, cashLine?.source === "manual" ? cashLine.currency : undefined),
199
+ [accountState, cashLine, financialsMap, tickers, totalsCurrency],
184
200
  );
185
201
  const exchangeRates = useFxRatesMap(trackedCurrencies);
186
202
  const conversionCurrencies = trackedCurrencies.some((currency) => currency !== totalsCurrency) ? trackedCurrencies : [];
187
203
  const fxStatus = summarizeFxRates(conversionCurrencies, exchangeRates, (currency) => getSharedMarketDataCoordinator()?.getFxEntry(currency));
188
204
  const fxStatusText = fxStatusLabel(fxStatus);
189
205
  const activeSort = resolveCollectionSortPreference(activeCollectionId, isPortfolioTab, collectionSorts);
206
+ const accountCurrency = accountState?.account.currency ?? "";
207
+ const convertAccountValue = useCallback(
208
+ (value: number) => convertCurrency(value, accountCurrency, totalsCurrency, exchangeRates),
209
+ [accountCurrency, exchangeRates, totalsCurrency],
210
+ );
211
+ const cashValue = cashLine == null ? null
212
+ : cashLine.source === "broker" ? convertAccountValue(cashLine.amount)
213
+ : convertCurrency(cashLine.amount, cashLine.currency, totalsCurrency, exchangeRates);
190
214
  // Only weights divide by the total: skip the walk when nothing shows one.
191
215
  const needsWeightTotal = isPortfolioTab
192
- && (viewMode === "grid" || columns.some((column) => column.id === "weight"));
193
- const portfolioTotalMarketValue = useThrottledMemo(
216
+ && (viewMode === "grid" || columns.some((column) => ALLOCATION_COLUMN_IDS.has(column.id)));
217
+ const weightHoldings = useThrottledMemo(
194
218
  () => needsWeightTotal ? calculatePortfolioSummaryTotals(
195
219
  tickers,
196
220
  financialsMap,
@@ -198,11 +222,13 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
198
222
  exchangeRates,
199
223
  isPortfolioTab,
200
224
  activeCollectionId,
201
- ).totalMktValue : undefined,
225
+ ).allocationHoldings : undefined,
202
226
  [financialsMap],
203
227
  [activeCollectionId, exchangeRates, isPortfolioTab, needsWeightTotal, tickers, totalsCurrency],
204
228
  WEIGHT_TOTAL_THROTTLE_MS,
205
229
  );
230
+ // Priced holdings plus cash, as `portfolio show` totals them.
231
+ const portfolioTotalMarketValue = weightHoldings ? allocationTotal(weightHoldings, cashValue) ?? undefined : undefined;
206
232
 
207
233
  // The header, footer and notices move with live quotes a few times a second,
208
234
  // not on every tick.
@@ -226,6 +252,7 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
226
252
  baseCurrency: totalsCurrency,
227
253
  exchangeRates,
228
254
  portfolioTotalMarketValue,
255
+ portfolioTargets,
229
256
  supplementalVersion: supplementalData.version,
230
257
  analystResearch: supplementalData.analystResearch,
231
258
  corporateActions: supplementalData.corporateActions,
@@ -234,6 +261,7 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
234
261
  activeCollectionId,
235
262
  exchangeRates,
236
263
  isPortfolioTab,
264
+ portfolioTargets,
237
265
  portfolioTotalMarketValue,
238
266
  supplementalData,
239
267
  totalsCurrency,
@@ -292,11 +320,16 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
292
320
  : null,
293
321
  [accountState],
294
322
  );
295
- const accountCurrency = accountState?.account.currency ?? "";
296
- const convertAccountValue = useCallback(
297
- (value: number) => convertCurrency(value, accountCurrency, totalsCurrency, exchangeRates),
298
- [accountCurrency, exchangeRates, totalsCurrency],
299
- );
323
+ // Cash entered by hand gets its own figures; a broker account's cash is already in the header.
324
+ const manualCash = useMemo(() => {
325
+ if (!isPortfolioTab || accountState || (cashLine == null && portfolioTargets?.[CASH_SYMBOL] == null)) return null;
326
+ const allocation = buildPortfolioAllocation({
327
+ holdings: portfolioSummaryTotals.allocationHoldings ?? [],
328
+ cashValue: cashValue ?? (cashLine ? Number.NaN : null),
329
+ targets: portfolioTargets,
330
+ });
331
+ return allocation.cash ? { ...allocation.cash, total: allocation.total } : null;
332
+ }, [accountState, cashLine, cashValue, isPortfolioTab, portfolioSummaryTotals, portfolioTargets]);
300
333
  const summarySegments = useMemo(() => buildPortfolioSummarySegments({
301
334
  totals: portfolioSummaryTotals,
302
335
  accountState: summaryAccountState,
@@ -304,7 +337,8 @@ export function PortfolioListPane({ focused, width, height }: PaneProps) {
304
337
  convertAccountValue,
305
338
  currency: totalsCurrency,
306
339
  baseCurrency: config.baseCurrency,
307
- }), [config.baseCurrency, convertAccountValue, isPortfolioTab, portfolioSummaryTotals, summaryAccountState, totalsCurrency]);
340
+ manualCash,
341
+ }), [config.baseCurrency, convertAccountValue, isPortfolioTab, manualCash, portfolioSummaryTotals, summaryAccountState, totalsCurrency]);
308
342
  // The header row sits in the pane's one-cell side padding, like the table.
309
343
  const summaryWidth = Math.max(0, width - 2);
310
344
  const summaryLayout = useMemo(() => layoutPortfolioSummaryHeader(summarySegments, summaryWidth, {
@@ -9,10 +9,11 @@ import { useAppInputCapture } from "../../../../state/app/input-capture";
9
9
  import { t, tf } from "../../../../i18n";
10
10
  import { getSharedRegistry } from "../../../registry";
11
11
  import { usePluginAppActions } from "../../../runtime";
12
+ import { isDialogOpen } from "../../../../ui/dialog-stack";
12
13
  import { colors, priceColor } from "../../../../theme/colors";
13
14
  import { formatPercentRaw } from "../../../../utils/format";
14
15
  import { formatMarketPrice } from "../../../../market-data/market/format";
15
- import { upsertTickerFromSearchResult } from "../../../../tickers/search";
16
+ import { listingChoiceQuery, upsertTickerFromSearchResult } from "../../../../tickers/search";
16
17
  import type { TickerRecord } from "../../../../types/ticker";
17
18
  import { addTickerToPortfolio, addTickerToWatchlist } from "../mutations";
18
19
  import { captureAttentionAction } from "../../../../telemetry/attention-counts";
@@ -20,6 +21,7 @@ import { publicTickerKey } from "../../../../utils/exchanges";
20
21
  import {
21
22
  IDLE_VALIDATION,
22
23
  isPlausibleTickerQuery,
24
+ exchangeLabelFromValidation,
23
25
  normalizeQuickAddQuery,
24
26
  resolveQuickAddValidation,
25
27
  tickerNameFromValidation,
@@ -56,6 +58,10 @@ function QuickAddPreview({
56
58
  return <Text fg={colors.textMuted}>{t(validation.message)}</Text>;
57
59
  }
58
60
 
61
+ if (validation.status === "choose") {
62
+ return <Text fg={colors.textMuted}>{t("Multiple listings")}</Text>;
63
+ }
64
+
59
65
  if (validation.status === "duplicate") {
60
66
  return <Text fg={colors.textMuted}>{tf("{symbol} already in {collection}", {
61
67
  symbol: validation.symbol,
@@ -71,6 +77,7 @@ function QuickAddPreview({
71
77
  : "-";
72
78
  const changeValue = quote?.changePercent;
73
79
  const name = tickerNameFromValidation(validation);
80
+ const exchange = exchangeLabelFromValidation(validation);
74
81
  const showSymbol = normalizeQuickAddQuery(validation.symbol) !== validation.query;
75
82
  const symbolPrefix = showSymbol ? `${validation.symbol} ` : "";
76
83
 
@@ -81,6 +88,7 @@ function QuickAddPreview({
81
88
  {formatPercentRaw(changeValue)}
82
89
  </Text>
83
90
  {name ? <Text fg={colors.textMuted}>{` ${name}`}</Text> : null}
91
+ {exchange ? <Text fg={colors.textDim}>{` ${exchange}`}</Text> : null}
84
92
  </Box>
85
93
  );
86
94
  }
@@ -129,6 +137,21 @@ export function QuickAddTickerInput({
129
137
  setValidation(IDLE_VALIDATION);
130
138
  }, []);
131
139
 
140
+ // `NET:` is the command bar's venue dropdown. Choosing a row adds it here.
141
+ const handOffListingChoice = useCallback((query: string) => {
142
+ validationSeqRef.current += 1;
143
+ if (!isDialogOpen()) {
144
+ dispatch({
145
+ type: "SET_COMMAND_BAR",
146
+ open: true,
147
+ query,
148
+ launch: { kind: "add-listing", collectionId, collectionKind },
149
+ });
150
+ }
151
+ resetInput();
152
+ blurInput();
153
+ }, [blurInput, collectionId, collectionKind, dispatch, resetInput]);
154
+
132
155
  useEffect(() => {
133
156
  onFocusChange?.(inputFocused && focused);
134
157
  }, [focused, inputFocused, onFocusChange]);
@@ -159,6 +182,15 @@ export function QuickAddTickerInput({
159
182
  return;
160
183
  }
161
184
 
185
+ if (listingChoiceQuery(query)) {
186
+ setValidation(IDLE_VALIDATION);
187
+ const timeoutId = setTimeout(() => {
188
+ if (validationSeqRef.current !== seq) return;
189
+ handOffListingChoice(query);
190
+ }, QUICK_ADD_DEBOUNCE_MS);
191
+ return () => clearTimeout(timeoutId);
192
+ }
193
+
162
194
  if (!isPlausibleTickerQuery(query)) {
163
195
  setValidation({ status: "missing", query, message: "Use a ticker symbol" });
164
196
  return;
@@ -174,12 +206,16 @@ export function QuickAddTickerInput({
174
206
  }, QUICK_ADD_DEBOUNCE_MS);
175
207
 
176
208
  return () => clearTimeout(timeoutId);
177
- }, [inputValue, validateQuery]);
209
+ }, [handOffListingChoice, inputValue, validateQuery]);
178
210
 
179
211
  const submitInput = useCallback(async (submittedValue?: string) => {
180
212
  const recordAttention = captureAttentionAction();
181
213
  const query = normalizeQuickAddQuery(submittedValue ?? inputValue);
182
214
  if (!query || submitting) return;
215
+ if (listingChoiceQuery(query)) {
216
+ handOffListingChoice(query);
217
+ return;
218
+ }
183
219
 
184
220
  setSubmitting(true);
185
221
  try {
@@ -189,6 +225,10 @@ export function QuickAddTickerInput({
189
225
  )
190
226
  ? validation
191
227
  : await validateQuery(query);
228
+ if (currentValidation.status === "choose") {
229
+ handOffListingChoice(`${query}:`);
230
+ return;
231
+ }
192
232
  setValidation(currentValidation);
193
233
 
194
234
  if (currentValidation.status === "duplicate") {
@@ -275,6 +315,7 @@ export function QuickAddTickerInput({
275
315
  collectionKind,
276
316
  collectionName,
277
317
  dispatch,
318
+ handOffListingChoice,
278
319
  inputValue,
279
320
  notify,
280
321
  onAdded,
@@ -1,7 +1,13 @@
1
1
  import { getSharedRegistry } from "../../../registry";
2
- import { resolveTickerSearch, type ResolvedTickerSearch } from "../../../../tickers/search";
2
+ import {
3
+ AmbiguousContractError,
4
+ AmbiguousTickerError,
5
+ resolveTickerSearch,
6
+ type ResolvedTickerSearch,
7
+ } from "../../../../tickers/search";
3
8
  import type { Quote } from "../../../../types/financials";
4
9
  import type { TickerRecord } from "../../../../types/ticker";
10
+ import { canonicalExchange, parsePublicTickerKey, publicTickerKey } from "../../../../utils/exchanges";
5
11
 
6
12
  const QUICK_ADD_MAX_QUERY_LENGTH = 32;
7
13
  const QUICK_ADD_SYMBOL_RE = /^[A-Z0-9][A-Z0-9.\-\s]*$/;
@@ -21,6 +27,8 @@ export type QuickAddValidation =
21
27
  | { status: "checking"; query: string }
22
28
  | (ResolvedQuickAdd & { status: "ready" })
23
29
  | (ResolvedQuickAdd & { status: "duplicate" })
30
+ /** The symbol names several listings and none is the default: the add row asks which. */
31
+ | { status: "choose"; query: string }
24
32
  | { status: "missing"; query: string; message: string }
25
33
  | { status: "error"; query: string; message: string };
26
34
 
@@ -73,6 +81,38 @@ export function tickerNameFromValidation(
73
81
  return validation.resolved.kind === "provider" ? validation.resolved.result.name : "";
74
82
  }
75
83
 
84
+ export function exchangeLabelFromValidation(
85
+ validation: Extract<QuickAddValidation, { status: "ready" | "duplicate" }>,
86
+ ): string {
87
+ if (validation.resolved.kind === "provider") {
88
+ const result = validation.resolved.result;
89
+ return result.exchange === "SMART" ? result.primaryExchange || result.exchange : result.exchange || "";
90
+ }
91
+ return validation.ticker?.metadata.exchange || "";
92
+ }
93
+
94
+ /**
95
+ * The symbol key can already store another listing. Only this listing's own
96
+ * record, and its cached quote, belong to this add.
97
+ */
98
+ function tickerForResolved(
99
+ resolved: ResolvedTickerSearch,
100
+ tickers: Map<string, TickerRecord>,
101
+ ): TickerRecord | null {
102
+ if (resolved.kind === "local") return resolved.ticker;
103
+ const result = resolved.result;
104
+ const exchange = canonicalExchange(result.exchange === "SMART" ? result.primaryExchange : result.exchange);
105
+ const bare = parsePublicTickerKey(resolved.symbol).symbol;
106
+ const qualified = publicTickerKey(bare, exchange || undefined);
107
+ const qualifiedTicker = qualified === bare ? undefined : tickers.get(qualified);
108
+ if (qualifiedTicker) return qualifiedTicker;
109
+ const saved = tickers.get(bare) ?? tickers.get(resolved.symbol) ?? null;
110
+ if (!saved) return null;
111
+ const savedExchange = canonicalExchange(saved.metadata.exchange);
112
+ if (exchange && savedExchange && exchange !== savedExchange) return null;
113
+ return saved;
114
+ }
115
+
76
116
  export async function resolveQuickAddValidation({
77
117
  query,
78
118
  collectionId,
@@ -108,8 +148,8 @@ export async function resolveQuickAddValidation({
108
148
  }
109
149
 
110
150
  const symbol = resolved.symbol;
111
- const ticker = resolved.kind === "local" ? resolved.ticker : (tickers.get(symbol) ?? null);
112
- const cachedQuote = financials.get(symbol)?.quote ?? null;
151
+ const ticker = tickerForResolved(resolved, tickers);
152
+ const cachedQuote = ticker ? financials.get(ticker.metadata.ticker)?.quote ?? null : null;
113
153
  let quote = cachedQuote;
114
154
  if (!quote) {
115
155
  try {
@@ -126,12 +166,15 @@ export async function resolveQuickAddValidation({
126
166
  return {
127
167
  status: tickerBelongsToCollection(ticker, collectionKind, collectionId) ? "duplicate" : "ready",
128
168
  query,
129
- symbol,
169
+ symbol: ticker?.metadata.ticker ?? symbol,
130
170
  resolved,
131
171
  ticker,
132
172
  quote,
133
173
  };
134
- } catch {
174
+ } catch (error) {
175
+ if (error instanceof AmbiguousTickerError && !(error instanceof AmbiguousContractError)) {
176
+ return { status: "choose", query };
177
+ }
135
178
  return { status: "error", query, message: "Ticker lookup failed" };
136
179
  }
137
180
  }
@@ -53,6 +53,11 @@ const PORTFOLIO_COLUMN_DEFS: ColumnConfig[] = [
53
53
  { id: "cost_basis", label: "COST", width: 10, align: "right", format: "compact" },
54
54
  { id: "mkt_value", label: "MKT VAL", width: 10, align: "right", format: "compact" },
55
55
  { id: "weight", label: "WEIGHT", width: 8, align: "right", format: "percent" },
56
+ // TARGET is the analyst price target; these are the portfolio's own target weights.
57
+ { id: "target_weight", label: "TGT WT", width: 7, align: "right", format: "percent" },
58
+ { id: "drift", label: "DRIFT", width: 8, align: "right", format: "percent" },
59
+ { id: "trade", label: "TRADE", width: 9, align: "right", format: "number" },
60
+ { id: "trade_value", label: "TRADE VAL", width: 10, align: "right", format: "compact" },
56
61
  { id: "day_pnl", label: "DAY", width: 10, align: "right", format: "compact" },
57
62
  { id: "pnl", label: "P&L", width: 10, align: "right", format: "compact" },
58
63
  { id: "pnl_pct", label: "P&L%", width: 8, align: "right", format: "percent" },
@@ -69,6 +74,10 @@ const PORTFOLIO_ONLY_COLUMN_IDS = new Set([
69
74
  "cost_basis",
70
75
  "mkt_value",
71
76
  "weight",
77
+ "target_weight",
78
+ "drift",
79
+ "trade",
80
+ "trade_value",
72
81
  "day_pnl",
73
82
  "pnl",
74
83
  "pnl_pct",
@@ -142,8 +151,26 @@ function resolveCollectionOptions(entries: CollectionEntry[]): PaneSettingOption
142
151
  }));
143
152
  }
144
153
 
154
+ /** Columns that read a portfolio's target weights. */
155
+ const TARGET_COLUMN_IDS = new Set(["target_weight", "drift", "trade", "trade_value"]);
156
+ /** What a portfolio with targets shows when the pane's columns name none of them. */
157
+ const REBALANCE_COLUMN_IDS = ["weight", "target_weight", "drift", "trade"];
158
+
159
+ /**
160
+ * A portfolio with target weights shows WEIGHT, TGT WT, DRIFT and TRADE beside
161
+ * its market value, unless the pane's columns already pick target columns.
162
+ */
163
+ function withTargetColumns(columnIds: string[]): string[] {
164
+ if (columnIds.some((id) => TARGET_COLUMN_IDS.has(id))) return columnIds;
165
+ const missing = REBALANCE_COLUMN_IDS.filter((id) => !columnIds.includes(id));
166
+ const anchor = columnIds.includes("weight") ? columnIds.indexOf("weight") : columnIds.indexOf("mkt_value");
167
+ const at = anchor >= 0 ? anchor + 1 : columnIds.length;
168
+ return [...columnIds.slice(0, at), ...missing, ...columnIds.slice(at)];
169
+ }
170
+
145
171
  function describeColumnOption(column: ColumnConfig): string {
146
172
  if (column.id === PRICE_SPARKLINE_COLUMN_ID) return "One-month price sparkline.";
173
+ if (TARGET_COLUMN_IDS.has(column.id)) return "Shown by default once the portfolio has target weights.";
147
174
  return PORTFOLIO_ONLY_COLUMN_IDS.has(column.id)
148
175
  ? "Visible only when this pane is showing a portfolio."
149
176
  : "Visible for watchlists and portfolios.";
@@ -222,8 +249,12 @@ export function resolvePortfolioPaneCollectionId(
222
249
  return resolveActiveCollectionId(currentCollectionId, visibleCollections);
223
250
  }
224
251
 
225
- export function resolveVisibleColumns(columnIds: string[], isPortfolioTab: boolean): ColumnConfig[] {
226
- const resolved = columnIds
252
+ export function resolveVisibleColumns(
253
+ columnIds: string[],
254
+ isPortfolioTab: boolean,
255
+ { targetWeights = false }: { targetWeights?: boolean } = {},
256
+ ): ColumnConfig[] {
257
+ const resolved = (isPortfolioTab && targetWeights ? withTargetColumns(columnIds) : columnIds)
227
258
  .map((columnId) => PORTFOLIO_COLUMNS_BY_ID.get(columnId))
228
259
  .filter((column): column is ColumnConfig => column != null)
229
260
  .filter((column) => isPortfolioTab || !PORTFOLIO_ONLY_COLUMN_IDS.has(column.id));
@@ -17,6 +17,7 @@ import {
17
17
  type BrokerSnapshotBasis,
18
18
  } from "../account-metrics";
19
19
  import { formatPortfolioAmount, type PortfolioSummaryTotals } from "./totals";
20
+ import { formatAllocationDrift, formatAllocationWeight, type PortfolioCashLine } from "../allocation";
20
21
  import { getMostRecentQuoteUpdate } from "../../../../market-data/quotes/time";
21
22
  import { fxStatusLabel, type FxRateStatus } from "../../../../utils/fx-status";
22
23
  import { t } from "../../../../i18n";
@@ -221,6 +222,7 @@ export function buildPortfolioSummarySegments({
221
222
  convertAccountValue = (value) => value,
222
223
  currency = "USD",
223
224
  baseCurrency = "USD",
225
+ manualCash = null,
224
226
  }: {
225
227
  totals: PortfolioSummaryTotals;
226
228
  accountState: PortfolioSummaryAccountState | null;
@@ -231,6 +233,8 @@ export function buildPortfolioSummarySegments({
231
233
  currency?: string;
232
234
  /** The app's base currency: amounts are bare only when both are USD. */
233
235
  baseCurrency?: string;
236
+ /** Cash entered by hand, in the totals currency, with the total it is weighed against. */
237
+ manualCash?: (PortfolioCashLine & { total: number | null }) | null;
234
238
  }): PortfolioSummarySegment[] {
235
239
  const money = (value: number | undefined, signed = false) => formatPortfolioAmount(value, currency, { signed, baseCurrency });
236
240
  if (!isPortfolioTab) {
@@ -241,7 +245,7 @@ export function buildPortfolioSummarySegments({
241
245
  ])]
242
246
  : [];
243
247
  }
244
- if (!totals.hasPositions && !accountState) return [];
248
+ if (!totals.hasPositions && !accountState && !manualCash) return [];
245
249
 
246
250
  const candidates: PortfolioSummarySegment[] = [];
247
251
  const account = accountState?.account;
@@ -257,6 +261,14 @@ export function buildPortfolioSummarySegments({
257
261
  ])
258
262
  : null;
259
263
 
264
+ // Holdings plus the cash, as weights divide by it; like Net Liq for a broker account.
265
+ if (manualCash) {
266
+ candidates.push(createSummarySegment("total", [
267
+ { text: "Total", tone: "label" },
268
+ { text: money(manualCash.total ?? Number.NaN), tone: "value", bold: true },
269
+ ]));
270
+ }
271
+
260
272
  if (netLiquidation != null) {
261
273
  candidates.push(createSummarySegment("netliq", [
262
274
  { text: "Net Liq", tone: "label" },
@@ -278,6 +290,17 @@ export function buildPortfolioSummarySegments({
278
290
 
279
291
  // A broker account always states its cash, so a missing balance reads as unknown rather than zero.
280
292
  if (account) candidates.push(accountValue("cash", "Cash", account.totalCashValue ?? Number.NaN)!);
293
+ if (manualCash) {
294
+ const drift = formatAllocationDrift(manualCash.drift);
295
+ candidates.push(createSummarySegment("cash", [
296
+ { text: "Cash", tone: "label" },
297
+ { text: money(manualCash.value), tone: "value", bold: true },
298
+ ...(manualCash.weight != null ? [{ text: `(${formatAllocationWeight(manualCash.weight)})`, tone: "muted" as const }] : []),
299
+ ...(manualCash.targetWeight != null && manualCash.drift != null
300
+ ? [{ text: drift, tone: "muted" as const, color: /[1-9]/.test(drift) ? priceColor(manualCash.drift) : undefined }]
301
+ : []),
302
+ ]));
303
+ }
281
304
 
282
305
  candidates.push(createSummarySegment("day", [
283
306
  { text: "Day", tone: "label" },
@@ -4,7 +4,9 @@ import { convertCurrency, formatCompactAmount } from "../../../../utils/format";
4
4
  import { getCurrencySymbol } from "../../../../market-data/market/format";
5
5
  import { getActiveQuoteDisplay } from "../../../../market-data/market/status";
6
6
  import { isQuoteStaleForCurrentSession } from "../../../../market-data/quotes/freshness";
7
+ import { headlineQuoteDisplay } from "../column-values";
7
8
  import { isManualPortfolio } from "../mutations";
9
+ import type { AllocationHolding } from "../allocation";
8
10
  import {
9
11
  getPortfolioPositionMetrics,
10
12
  getPortfolioQuoteDisplay,
@@ -46,6 +48,8 @@ export interface PortfolioSummaryTotals {
46
48
  livePriced?: boolean;
47
49
  /** Lots with a current quote. Broker account snapshots move by these. */
48
50
  pricedLots?: PricedPortfolioLot[];
51
+ /** Every ticker of a portfolio valued for weights and targets (see allocation.ts). */
52
+ allocationHoldings?: AllocationHolding[];
49
53
  }
50
54
 
51
55
  const CURRENCY_CODE = /^[A-Z]{3}$/;
@@ -112,6 +116,7 @@ export function calculatePortfolioSummaryTotals(
112
116
  const unavailableConversions = new Set<string>();
113
117
  let livePriced = true;
114
118
  const pricedLots: PricedPortfolioLot[] = [];
119
+ const allocationHoldings: AllocationHolding[] = [];
115
120
  const now = Date.now();
116
121
  const toBase = (value: number, currency: string) => {
117
122
  const converted = convertCurrency(value, currency, totalsCurrency, exchangeRates);
@@ -127,8 +132,10 @@ export function calculatePortfolioSummaryTotals(
127
132
  const quoteCurrency = quote?.currency || ticker.metadata.currency || "USD";
128
133
 
129
134
  if (!isPortfolio) {
130
- if (activeQuote?.changePercent != null) {
131
- watchlistChangeSum += activeQuote.changePercent;
135
+ // The CHG% column's value, so Avg Day is the mean of that column.
136
+ const changePercent = headlineQuoteDisplay(activeQuote, quote)?.changePercent;
137
+ if (changePercent != null) {
138
+ watchlistChangeSum += changePercent;
132
139
  watchlistCount++;
133
140
  }
134
141
  continue;
@@ -139,20 +146,24 @@ export function calculatePortfolioSummaryTotals(
139
146
  }, quote);
140
147
  activeQuote = getPortfolioQuoteDisplay(positionMetrics, quote);
141
148
  const { totalPriceUnits, grossPriceUnits, totalCost } = positionMetrics;
142
- if (positionMetrics.positionCount === 0) continue;
149
+ if (positionMetrics.positionCount === 0) {
150
+ // Not held, so a missing rate is no gap in the totals: it only leaves the trade in units out.
151
+ const unitPrice = activeQuote ? convertCurrency(activeQuote.price, quoteCurrency, totalsCurrency, exchangeRates) : null;
152
+ allocationHoldings.push({ symbol: ticker.metadata.ticker, held: false, marketValue: 0, units: 0, unitPrice });
153
+ continue;
154
+ }
155
+ const toBaseQuote = (value: number) => toBase(value, quoteCurrency);
156
+ const currentUnitPrice = activeQuote ? toBaseQuote(activeQuote.price) : null;
143
157
  hasPositions = true;
144
158
  hasShorts ||= positionMetrics.hasShorts;
145
159
  totalCostBasis += totalCost;
146
160
  if (!positionMetrics.hasCostBasis) unavailableCostSymbols.add(ticker.metadata.ticker);
147
161
 
148
- const toBaseQuote = (value: number) => toBase(value, quoteCurrency);
149
- const positionPnl = resolvePortfolioPositionPnl(positionMetrics,
150
- activeQuote ? toBaseQuote(activeQuote.price) : null);
162
+ const positionPnl = resolvePortfolioPositionPnl(positionMetrics, currentUnitPrice);
151
163
  signedUnrealizedPnl += positionPnl.value ?? Number.NaN;
152
164
  pnlBases.add(positionPnl.basis);
153
165
  if (positionPnl.basis === "broker-snapshot" || positionPnl.basis === "mixed") brokerPnlSymbols.add(ticker.metadata.ticker);
154
166
 
155
- const currentUnitPrice = activeQuote ? toBaseQuote(activeQuote.price) : null;
156
167
  const freshQuote = currentUnitPrice != null && Number.isFinite(currentUnitPrice)
157
168
  && !!quote && !isQuoteStaleForCurrentSession(quote, now);
158
169
  if (!freshQuote || quote.dataSource === "delayed" || quote.dataSource === "snapshot") livePriced = false;
@@ -172,6 +183,13 @@ export function calculatePortfolioSummaryTotals(
172
183
  }
173
184
 
174
185
  const marketValue = resolvePortfolioMarketValue(positionMetrics, currentUnitPrice);
186
+ allocationHoldings.push({
187
+ symbol: ticker.metadata.ticker,
188
+ held: true,
189
+ marketValue: marketValue?.net ?? null,
190
+ units: positionMetrics.totalShares,
191
+ unitPrice: currentUnitPrice,
192
+ });
175
193
  if (marketValue) {
176
194
  totalMktValue += marketValue.gross;
177
195
  netMktValue += marketValue.net;
@@ -216,5 +234,6 @@ export function calculatePortfolioSummaryTotals(
216
234
  ...(unavailableConversions.size > 0 ? { unavailableConversions: [...unavailableConversions].sort() } : {}),
217
235
  ...(isPortfolio ? { livePriced: hasPositions && livePriced } : {}),
218
236
  ...(pricedLots.length > 0 ? { pricedLots } : {}),
237
+ ...(isPortfolio ? { allocationHoldings } : {}),
219
238
  };
220
239
  }
@@ -4,7 +4,9 @@ import { powerQuery } from "./query";
4
4
  import { POWER_TABS, powerTab } from "./model";
5
5
 
6
6
  export const powerHeadless: HeadlessPaneDefinition<"bundle"> = {
7
- shape: "bundle", argument: { kind: "free-text", optional: true, placeholder: "ticker", description: "Optional listed developer or utility ticker, with exchange suffix where needed." },
7
+ shape: "bundle",
8
+ freshness: { source: "Grid operator queues and utility filings", status: "not-a-feed", basis: "published records" },
9
+ argument: { kind: "free-text", optional: true, placeholder: "ticker", description: "Optional listed developer or utility ticker, with exchange suffix where needed." },
8
10
  options: [
9
11
  { key: "tab", type: "enum", settingKey: "tab", defaultValue: "queue", values: POWER_TABS.map(({ value }) => ({ value })), description: "Queue, history, outcomes, large loads, utility exposure, capacity or coverage." },
10
12
  ...["country", "region", "fuel", "status", "search", "sourceId", "from", "to"].map((key) => ({ key, type: "string" as const, settingKey: key, description: `Filter by ${key}.` })),