gloomberb 0.16.1 → 0.16.3

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 (643) 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 +26 -8
  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 +2 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/paths.ts +30 -1
  10. package/src/api-client/perps.ts +37 -0
  11. package/src/api-client/request.ts +5 -2
  12. package/src/api-client/types.ts +2 -0
  13. package/src/brokers/account-cache.ts +69 -0
  14. package/src/cli/command-options.ts +74 -0
  15. package/src/cli/commands/command-utils.ts +37 -0
  16. package/src/cli/commands/crypto-hints.ts +75 -0
  17. package/src/cli/commands/market.ts +560 -136
  18. package/src/cli/commands/overview.ts +136 -48
  19. package/src/cli/commands/ticker.ts +220 -67
  20. package/src/cli/desktop-pane-shot.ts +37 -4
  21. package/src/cli/freshness.ts +61 -0
  22. package/src/cli/help.ts +27 -6
  23. package/src/cli/helpers.ts +4 -8
  24. package/src/cli/history-rows.ts +187 -15
  25. package/src/cli/index.ts +23 -8
  26. package/src/cli/listing-arg.ts +321 -0
  27. package/src/cli/options.ts +5 -1
  28. package/src/cli/pane-functions/access-gate.ts +42 -0
  29. package/src/cli/pane-functions/capabilities.ts +5 -0
  30. package/src/cli/pane-functions/catalog.ts +28 -1
  31. package/src/cli/pane-functions/data.ts +3 -1
  32. package/src/cli/pane-functions/dom.ts +87 -16
  33. package/src/cli/pane-functions/freshness.ts +400 -0
  34. package/src/cli/pane-functions/function-help.ts +31 -22
  35. package/src/cli/pane-functions/headless.ts +201 -41
  36. package/src/cli/pane-functions/index.ts +24 -6
  37. package/src/cli/pane-functions/options.ts +3 -0
  38. package/src/cli/pane-functions/report.ts +12 -1
  39. package/src/cli/pane-functions/resolver.ts +63 -9
  40. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  41. package/src/cli/pane-functions/screenshot.ts +11 -3
  42. package/src/cli/registry.ts +6 -3
  43. package/src/cli/report-tables.ts +460 -0
  44. package/src/cli/result.ts +53 -29
  45. package/src/cli/ticker-resolution.ts +7 -5
  46. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  47. package/src/components/chart/composite/drawing-store.ts +59 -0
  48. package/src/components/chart/composite/legend.tsx +319 -0
  49. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  50. package/src/components/chart/composite/panel-gestures.ts +59 -0
  51. package/src/components/chart/composite/panel-labels.ts +107 -0
  52. package/src/components/chart/composite/panel-surface.tsx +876 -0
  53. package/src/components/chart/composite/tool-catalog.ts +98 -0
  54. package/src/components/chart/composite/toolbar.tsx +186 -0
  55. package/src/components/chart/composite/tools.ts +8 -0
  56. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  57. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  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/ticker-search/actions.ts +5 -0
  62. package/src/components/command-bar/workflow/ops.ts +1 -1
  63. package/src/components/command-bar/workflow/tickers.ts +6 -0
  64. package/src/components/data-table/export.ts +6 -51
  65. package/src/components/data-table/view.tsx +32 -11
  66. package/src/components/feedback-dialog.tsx +2 -1
  67. package/src/components/form-modal/field-row.tsx +2 -2
  68. package/src/components/layout/detached-pane-shell.tsx +6 -3
  69. package/src/components/layout/pane/content.tsx +23 -10
  70. package/src/components/layout/pane/error-boundary.tsx +103 -0
  71. package/src/components/layout/pane/footer/registration.tsx +68 -23
  72. package/src/components/layout/pane/header.tsx +11 -11
  73. package/src/components/layout/shell/active-drag.ts +67 -35
  74. package/src/components/layout/shell/cursor-occlusion.ts +6 -5
  75. package/src/components/layout/shell/drag/index.ts +12 -7
  76. package/src/components/layout/shell/drag/live.ts +122 -0
  77. package/src/components/layout/shell/drag/overlays.tsx +179 -35
  78. package/src/components/layout/shell/drag/runtime.ts +62 -50
  79. package/src/components/layout/shell/drag/slide.ts +10 -0
  80. package/src/components/layout/shell/index.tsx +37 -51
  81. package/src/components/layout/shell/menu.ts +2 -1
  82. package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
  83. package/src/components/layout/shell/native/surfaces.ts +30 -14
  84. package/src/components/layout/shell/pane/actions.ts +2 -1
  85. package/src/components/layout/shell/pane/layers.tsx +419 -168
  86. package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
  87. package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
  88. package/src/components/metric-treemap/heat-surface.tsx +43 -16
  89. package/src/components/metric-treemap/heat-tiles.ts +18 -0
  90. package/src/components/metric-treemap/layout.ts +2 -0
  91. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  92. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  93. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  94. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  95. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  96. package/src/components/ticker/list-table-view.tsx +13 -1
  97. package/src/components/ui/fields.tsx +8 -0
  98. package/src/components/ui/range-track.tsx +10 -3
  99. package/src/components/ui/status.tsx +8 -2
  100. package/src/components/ui/tabs.tsx +7 -4
  101. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  102. package/src/data/config/store/normalize.ts +17 -1
  103. package/src/data/json-persistence.ts +17 -3
  104. package/src/data/json-storage.ts +2 -0
  105. package/src/data/memory-resource-store.ts +46 -0
  106. package/src/i18n/es.ts +19 -1
  107. package/src/i18n/ja.ts +19 -1
  108. package/src/i18n/ko.ts +19 -1
  109. package/src/i18n/zh-cn.ts +19 -1
  110. package/src/i18n/zh-tw.ts +19 -1
  111. package/src/market-data/coordinator/chart.ts +1 -1
  112. package/src/market-data/coordinator/quotes.ts +23 -4
  113. package/src/market-data/fx-closes.ts +72 -0
  114. package/src/market-data/market/freshness.ts +123 -6
  115. package/src/market-data/market/session-close-note.ts +57 -0
  116. package/src/market-data/market/status.ts +151 -0
  117. package/src/market-data/published-apac-sessions.ts +66 -0
  118. package/src/market-data/quotes/contributions.ts +2 -0
  119. package/src/market-data/quotes/freshness.ts +5 -0
  120. package/src/market-data/quotes/resolution.ts +2 -0
  121. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  122. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  123. package/src/plugins/builtin/alerts/cli.ts +10 -5
  124. package/src/plugins/builtin/alerts/index.tsx +1 -0
  125. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  126. package/src/plugins/builtin/analytics/pane-model.ts +10 -6
  127. package/src/plugins/builtin/analytics/risk-client.ts +191 -66
  128. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  129. package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
  130. package/src/plugins/builtin/analytics/risk-model.ts +45 -17
  131. package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
  132. package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
  133. package/src/plugins/builtin/attention/headless.ts +6 -4
  134. package/src/plugins/builtin/attention/index.tsx +1 -1
  135. package/src/plugins/builtin/attention/pane.tsx +2 -2
  136. package/src/plugins/builtin/awards/headless.ts +1 -0
  137. package/src/plugins/builtin/awards/pane.tsx +1 -1
  138. package/src/plugins/builtin/backtest/headless.ts +1 -0
  139. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  140. package/src/plugins/builtin/buildout/index.tsx +1 -0
  141. package/src/plugins/builtin/catalysts/detail.tsx +1 -1
  142. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  143. package/src/plugins/builtin/cds/headless.ts +2 -0
  144. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  145. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  146. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  147. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  148. package/src/plugins/builtin/chat/channels.ts +19 -3
  149. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  150. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  151. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  152. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  153. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  154. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  155. package/src/plugins/builtin/chat/index.tsx +1 -0
  156. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  157. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  158. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  159. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  160. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  161. package/src/plugins/builtin/chat/message/types.ts +14 -2
  162. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  163. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  164. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  165. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  166. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  167. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  168. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  169. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  170. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  171. package/src/plugins/builtin/company-attention/pane.tsx +2 -2
  172. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  173. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  174. package/src/plugins/builtin/correlation/compute.ts +59 -16
  175. package/src/plugins/builtin/correlation/geo.ts +34 -0
  176. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  177. package/src/plugins/builtin/correlation/headless.ts +42 -8
  178. package/src/plugins/builtin/correlation/history.ts +2 -0
  179. package/src/plugins/builtin/correlation/index.tsx +68 -14
  180. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  181. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  182. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  183. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  184. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  185. package/src/plugins/builtin/correlation/settings.ts +1 -1
  186. package/src/plugins/builtin/cot/headless.ts +6 -3
  187. package/src/plugins/builtin/cot/index.tsx +3 -3
  188. package/src/plugins/builtin/cot/model.ts +36 -3
  189. package/src/plugins/builtin/cpi/headless.ts +4 -0
  190. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  191. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  192. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  193. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  194. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  195. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  196. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  197. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  198. package/src/plugins/builtin/doe/headless.ts +7 -0
  199. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  200. package/src/plugins/builtin/earnings/headless.ts +5 -0
  201. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  202. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  203. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  204. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  205. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  206. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  207. package/src/plugins/builtin/econ/index.tsx +1 -0
  208. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  209. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  210. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  211. package/src/plugins/builtin/executives/index.tsx +1 -0
  212. package/src/plugins/builtin/exposure/headless.ts +3 -1
  213. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  214. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  215. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  216. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  217. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  218. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  219. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  220. package/src/plugins/builtin/gpu/headless.ts +7 -3
  221. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  222. package/src/plugins/builtin/gpu/model.ts +27 -1
  223. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  224. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  225. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  226. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  227. package/src/plugins/builtin/holders/client.ts +3 -6
  228. package/src/plugins/builtin/holders/format.ts +31 -1
  229. package/src/plugins/builtin/holders/headless.ts +161 -6
  230. package/src/plugins/builtin/holders/index.tsx +10 -3
  231. package/src/plugins/builtin/holders/pane.tsx +42 -16
  232. package/src/plugins/builtin/holders/report-header.ts +136 -0
  233. package/src/plugins/builtin/holders/table-model.ts +20 -5
  234. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  235. package/src/plugins/builtin/holders/types.ts +2 -1
  236. package/src/plugins/builtin/insider/headless.ts +2 -0
  237. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  238. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  239. package/src/plugins/builtin/jobs/headless.ts +1 -0
  240. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  241. package/src/plugins/builtin/kelly-sizer/pane.tsx +12 -6
  242. package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
  243. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  244. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  245. package/src/plugins/builtin/market-heatmap/data.ts +2 -0
  246. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  247. package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
  248. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  249. package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
  250. package/src/plugins/builtin/market-movers/headless.ts +2 -0
  251. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  252. package/src/plugins/builtin/members/client.ts +20 -3
  253. package/src/plugins/builtin/members/headless.ts +5 -3
  254. package/src/plugins/builtin/members/model.ts +10 -2
  255. package/src/plugins/builtin/members/pane.tsx +23 -6
  256. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  257. package/src/plugins/builtin/mna/headless.ts +1 -0
  258. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  259. package/src/plugins/builtin/news/headless.ts +2 -0
  260. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  261. package/src/plugins/builtin/notes/cli.ts +14 -6
  262. package/src/plugins/builtin/notes/index.tsx +1 -0
  263. package/src/plugins/builtin/openfda/index.tsx +1 -0
  264. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  265. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  266. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  267. package/src/plugins/builtin/pe-band/client.ts +48 -3
  268. package/src/plugins/builtin/pe-band/headless.ts +25 -7
  269. package/src/plugins/builtin/pe-band/model.ts +92 -16
  270. package/src/plugins/builtin/pe-band/pane.tsx +33 -16
  271. package/src/plugins/builtin/perps/client.ts +50 -3
  272. package/src/plugins/builtin/perps/headless.ts +144 -16
  273. package/src/plugins/builtin/perps/index.tsx +6 -6
  274. package/src/plugins/builtin/perps/model.ts +189 -12
  275. package/src/plugins/builtin/perps/pane.tsx +249 -48
  276. package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
  277. package/src/plugins/builtin/portfolio-list/allocation.ts +248 -0
  278. package/src/plugins/builtin/portfolio-list/cached-account.ts +42 -0
  279. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  280. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  281. package/src/plugins/builtin/portfolio-list/cli/render.ts +232 -39
  282. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  283. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  284. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  285. package/src/plugins/builtin/portfolio-list/headless.ts +100 -16
  286. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  287. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  288. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  289. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  290. package/src/plugins/builtin/portfolio-list/pane/index.tsx +53 -16
  291. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  292. package/src/plugins/builtin/portfolio-list/summary/index.tsx +46 -5
  293. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
  294. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  295. package/src/plugins/builtin/power/headless.ts +3 -1
  296. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  297. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  298. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  299. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  300. package/src/plugins/builtin/research/events-headless.ts +2 -0
  301. package/src/plugins/builtin/research/headless.ts +2 -0
  302. package/src/plugins/builtin/research/index.tsx +1 -0
  303. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  304. package/src/plugins/builtin/research/relative-valuation-model.ts +18 -6
  305. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  306. package/src/plugins/builtin/research-search/index.tsx +1 -0
  307. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  308. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  309. package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
  310. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  311. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  312. package/src/plugins/builtin/scanner/headless.ts +14 -0
  313. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  314. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  315. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  316. package/src/plugins/builtin/sec/forms.ts +12 -0
  317. package/src/plugins/builtin/sec/headless.ts +2 -0
  318. package/src/plugins/builtin/sectors/client.ts +1 -0
  319. package/src/plugins/builtin/sectors/headless.ts +9 -1
  320. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  321. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  322. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  323. package/src/plugins/builtin/shared/members-menu.tsx +260 -0
  324. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  325. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  326. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  327. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  328. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  329. package/src/plugins/builtin/short-volume/pane.tsx +1 -1
  330. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  331. package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
  332. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  333. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  334. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  335. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  336. package/src/plugins/builtin/themes/headless.ts +3 -0
  337. package/src/plugins/builtin/themes/pane.tsx +3 -0
  338. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  339. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  340. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
  341. package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
  342. package/src/plugins/builtin/ticker-detail/headless.ts +27 -5
  343. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  344. package/src/plugins/builtin/ticker-detail/overview/model.ts +17 -5
  345. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +27 -26
  346. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  347. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  348. package/src/plugins/builtin/volatility/headless.ts +6 -1
  349. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  350. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +159 -0
  351. package/src/plugins/builtin/world-venue-map/basemap.ts +232 -0
  352. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  353. package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
  354. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  355. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  356. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  357. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  358. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  359. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  360. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +448 -0
  361. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  362. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  363. package/src/plugins/builtin/world-venue-map/index.ts +69 -6
  364. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +565 -0
  365. package/src/plugins/builtin/world-venue-map/layers.ts +406 -0
  366. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  367. package/src/plugins/builtin/world-venue-map/map.tsx +557 -85
  368. package/src/plugins/builtin/world-venue-map/model.ts +23 -4
  369. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +202 -0
  370. package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
  371. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  372. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  373. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  374. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  375. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  376. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  377. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  378. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  379. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  380. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  381. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  382. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  383. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  384. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  385. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  386. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  387. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  388. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  389. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  390. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  391. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  392. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  393. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  394. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  395. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  396. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  397. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  398. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  399. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  400. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  401. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  402. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  403. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  404. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  405. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  406. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  407. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  408. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  409. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  410. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  411. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  412. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  413. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  414. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  415. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  416. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  417. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  418. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  524. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  525. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  526. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  527. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  528. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  529. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  530. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  531. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  532. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  533. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  534. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  535. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  536. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  537. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  538. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  539. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  540. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  541. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  542. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  543. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  544. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  545. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  546. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  547. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  548. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  549. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  550. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  551. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  552. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  553. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  554. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  555. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  556. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  557. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  558. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  559. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  560. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  561. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  562. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  563. package/src/plugins/builtin/world-venue-map/pane.tsx +35 -44
  564. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  565. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  566. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  567. package/src/plugins/loader.ts +13 -1
  568. package/src/plugins/registry/pane-settings.ts +1 -0
  569. package/src/renderers/browser/app-services.ts +3 -1
  570. package/src/renderers/dom/build-assets.ts +81 -3
  571. package/src/renderers/dom/data-table/dom.ts +31 -0
  572. package/src/renderers/dom/data-table/index.tsx +5 -0
  573. package/src/renderers/dom/data-table/row.tsx +2 -0
  574. package/src/renderers/dom/desktop/controls.tsx +7 -3
  575. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  576. package/src/renderers/dom/desktop/popover.tsx +73 -14
  577. package/src/renderers/dom/host/box.tsx +113 -17
  578. package/src/renderers/dom/host/drag-shield.ts +24 -0
  579. package/src/renderers/dom/host/input.tsx +14 -3
  580. package/src/renderers/dom/host/live-frame.ts +54 -0
  581. package/src/renderers/dom/host/mouse.ts +8 -1
  582. package/src/renderers/dom/host/scroll-box.tsx +6 -5
  583. package/src/renderers/dom/host/tabs.tsx +3 -2
  584. package/src/renderers/dom/styles.css +16 -9
  585. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
  586. package/src/renderers/electrobun/bun/desktop/backend.ts +2 -0
  587. package/src/renderers/electrobun/bun/desktop/initialization.ts +13 -0
  588. package/src/renderers/electrobun/shared/protocol.ts +10 -1
  589. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  590. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -0
  591. package/src/renderers/electrobun/view/host/native.ts +0 -10
  592. package/src/renderers/electrobun/view/host/window-move.ts +28 -0
  593. package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
  594. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  595. package/src/renderers/electrobun/view/ui-host.tsx +2 -5
  596. package/src/renderers/opentui/host.tsx +5 -0
  597. package/src/renderers/opentui/ui-host.tsx +7 -1
  598. package/src/sources/gloomberb-cloud/index.ts +25 -4
  599. package/src/sources/gloomberb-cloud/normalizers.ts +43 -23
  600. package/src/sources/provider-router/batches.ts +3 -3
  601. package/src/sources/provider-router/cached-routes.ts +4 -1
  602. package/src/sources/provider-router/financial-routes.ts +2 -2
  603. package/src/sources/provider-router/financials.ts +76 -12
  604. package/src/sources/provider-router/history.ts +15 -10
  605. package/src/sources/provider-router/primary.ts +2 -2
  606. package/src/sources/sec-registrant.ts +75 -0
  607. package/src/state/app/context/index.tsx +24 -8
  608. package/src/state/hooks/quote-streaming.ts +41 -26
  609. package/src/state/pane-scroll-registry.tsx +67 -35
  610. package/src/sync/core-contributors.ts +4 -0
  611. package/src/telemetry/crash-reports.ts +4 -1
  612. package/src/test-support/cli-context.ts +10 -2
  613. package/src/test-support/margin-account.ts +108 -0
  614. package/src/theme/heat-colors.ts +266 -84
  615. package/src/time-series/resolution.ts +15 -0
  616. package/src/time-series/resolve.ts +1 -1
  617. package/src/time-series/use-chart-resolution.ts +1 -1
  618. package/src/types/context-menu.ts +6 -0
  619. package/src/types/data-provider.ts +2 -0
  620. package/src/types/financials.ts +35 -3
  621. package/src/types/headless.ts +79 -2
  622. package/src/types/plugin.ts +20 -1
  623. package/src/types/ticker.ts +15 -0
  624. package/src/ui/host.tsx +26 -0
  625. package/src/ui/index.tsx +8 -3
  626. package/src/ui/scroll-box-axis.ts +26 -0
  627. package/src/updater/index.ts +9 -11
  628. package/src/utils/async-deadline.ts +21 -0
  629. package/src/utils/cli-output.ts +5 -1
  630. package/src/utils/crypto-pair.ts +41 -0
  631. package/src/utils/currency-units.ts +19 -0
  632. package/src/utils/depositary-receipt.ts +70 -0
  633. package/src/utils/display-number.ts +63 -0
  634. package/src/utils/exchanges.ts +72 -0
  635. package/src/utils/fire-and-forget.ts +24 -0
  636. package/src/utils/format.ts +13 -0
  637. package/src/utils/fundamentals.ts +17 -1
  638. package/src/utils/price-earnings.ts +70 -3
  639. package/src/utils/price-history-integrity.ts +19 -6
  640. package/src/utils/price-history.ts +58 -13
  641. package/src/utils/rpc-timeout-error.ts +27 -0
  642. package/src/utils/sec.ts +13 -1
  643. package/src/utils/utc-time.ts +79 -0
@@ -1,14 +1,10 @@
1
1
  import { createBaseConverter } from "../../../../cli/base-converter";
2
2
  import { withMarketData } from "../../../../cli/scoped-context";
3
- import {
4
- countCollectionTickers,
5
- formatSignedCurrency,
6
- } from "../../../../cli/helpers";
3
+ import { countCollectionTickers } from "../../../../cli/helpers";
7
4
  import {
8
5
  cliStyles,
9
6
  colorBySign,
10
7
  renderSection,
11
- renderStats,
12
8
  renderTable,
13
9
  } from "../../../../utils/cli-output";
14
10
  import { formatCompact, formatPercentRaw } from "../../../../utils/format";
@@ -24,6 +20,24 @@ import type { MarketContext } from "../../../../cli/types";
24
20
  import type { Portfolio, TickerPosition, TickerRecord } from "../../../../types/ticker";
25
21
  import { instrumentFromTicker } from "../../../../market-data/request-types";
26
22
  import { toMarketDataContext } from "../../../../market-data/selectors";
23
+ import { cliFreshnessFooter } from "../../../../cli/result";
24
+ import { quotesFreshness } from "../../../../cli/freshness";
25
+ import type { BrokerAccount } from "../../../../types/trading";
26
+ import {
27
+ BROKER_ACCOUNT_MISSING_NOTE,
28
+ CASH_SYMBOL,
29
+ buildPortfolioAllocation,
30
+ describeTargetSum,
31
+ formatAllocationDrift,
32
+ formatAllocationMoney,
33
+ formatAllocationWeight,
34
+ formatTradeUnits,
35
+ hasTargetWeights,
36
+ resolvePortfolioCash,
37
+ type AllocationHolding,
38
+ type PortfolioAllocation,
39
+ } from "../allocation";
40
+ import { findCachedPortfolioAccount } from "../cached-account";
27
41
 
28
42
  /** Money prices pad to the currency's minor unit ($337.90, not $337.9), as the ticker view does. */
29
43
  function priceFormatOptions(quote: Parameters<typeof quoteFormatOptions>[0] & { currency?: string }, assetCategory?: string) {
@@ -141,6 +155,8 @@ interface PortfolioPositionValue {
141
155
 
142
156
  export interface PortfolioValuation {
143
157
  positions: PortfolioPositionValue[];
158
+ /** One per ticker, for weights and targets. */
159
+ holdings: AllocationHolding[];
144
160
  totalPnl: number;
145
161
  unavailablePnl: Set<string>;
146
162
  unavailableCost: Set<string>;
@@ -175,6 +191,7 @@ export async function valuePortfolioPositions({
175
191
  const unavailableMarketValue = new Set<string>();
176
192
  const brokerPnlSymbols = new Set<string>();
177
193
  const values: PortfolioPositionValue[] = [];
194
+ const holdings: AllocationHolding[] = [];
178
195
  const known = (value: number | null | undefined): number | null => value != null && Number.isFinite(value) ? value : null;
179
196
 
180
197
  for (const ticker of tickers) {
@@ -184,6 +201,9 @@ export async function valuePortfolioPositions({
184
201
  const activeQuote = displayedQuote && Number.isFinite(displayedQuote.price) ? displayedQuote : null;
185
202
 
186
203
  if (positions.length === 0) {
204
+ const quoteCurrency = quote?.currency || ticker.metadata.currency || baseCurrency;
205
+ const unitPrice = activeQuote ? known(await toBase(activeQuote.price, quoteCurrency)) : null;
206
+ holdings.push({ symbol: ticker.metadata.ticker, held: false, marketValue: 0, units: 0, unitPrice });
187
207
  values.push({ ticker, quote, activeQuote, position: null, metrics: null, pnl: null,
188
208
  row: { symbol: ticker.metadata.ticker, exchange: ticker.metadata.exchange, shares: null, avgCost: null,
189
209
  positionCurrency: null, quotePrice: known(activeQuote?.price), quoteCurrency: quote?.currency ?? null,
@@ -191,6 +211,8 @@ export async function valuePortfolioPositions({
191
211
  continue;
192
212
  }
193
213
 
214
+ const holding: AllocationHolding = { symbol: ticker.metadata.ticker, held: true, marketValue: 0, units: 0, unitPrice: null };
215
+ holdings.push(holding);
194
216
  for (const position of positions) {
195
217
  const quoteCurrency = quote?.currency || ticker.metadata.currency || baseCurrency;
196
218
  const metrics = getPortfolioPositionMetrics({ ...ticker, metadata: { ...ticker.metadata, positions: [position] } }, id, quoteCurrency, undefined, quote);
@@ -212,24 +234,72 @@ export async function valuePortfolioPositions({
212
234
  if (pnl != null && Number.isFinite(pnl)) totalPnl += pnl;
213
235
  else unavailablePnl.add(ticker.metadata.ticker);
214
236
  const direction = metrics.totalShares < 0 ? -1 : 1;
237
+ const marketValue = currentValueBase == null ? null : known(direction * currentValueBase);
238
+ holding.marketValue = holding.marketValue == null || marketValue == null ? null : holding.marketValue + marketValue;
239
+ holding.units += metrics.totalShares;
240
+ holding.unitPrice ??= valuationQuote ? known(await toBase(valuationQuote.price, quoteCurrency)) : null;
215
241
  values.push({ ticker, quote, activeQuote, position, metrics, pnl,
216
242
  row: { symbol: ticker.metadata.ticker, exchange: ticker.metadata.exchange,
217
243
  shares: metrics.totalShares, avgCost: known(position.avgCost), positionCurrency,
218
244
  priceBasis: position.priceBasis ?? null, quantityUnit: metrics.priceBasis === "percent-of-par" ? "face" : null, quotePriceBasis: quote?.priceBasis ?? null,
219
245
  quotePrice: known(activeQuote?.price), quoteCurrency, quoteAsOf: quote?.lastUpdated ?? null,
220
- costBasis: known(direction * costBasisBase), marketValue: currentValueBase == null ? null : known(direction * currentValueBase),
246
+ costBasis: known(direction * costBasisBase), marketValue,
221
247
  unrealizedPnl: known(pnl), baseCurrency: currency, dateAcquired: position.dateAcquired ?? null,
222
248
  pnlBasis: selectedPnl.basis, brokerUnrealizedPnl: known(position.unrealizedPnl), brokerPnlCurrency: positionCurrency, brokerPnlAsOf: null } });
223
249
  }
224
250
  }
225
251
 
226
- return { positions: values, totalPnl, unavailablePnl, unavailableCost, unavailableMarketValue, brokerPnlSymbols };
252
+ return { positions: values, holdings, totalPnl, unavailablePnl, unavailableCost, unavailableMarketValue, brokerPnlSymbols };
253
+ }
254
+
255
+ /** A portfolio's cash line, as `portfolio show` and `fn PF` report it. */
256
+ export interface PortfolioCashReport {
257
+ /** In the cash's own currency. */
258
+ amount: number;
259
+ currency: string;
260
+ /** Recorded with `portfolio cash set`, or reported by the broker account. */
261
+ source: "manual" | "broker";
262
+ /** In the portfolio's currency; null when the rate is unavailable. */
263
+ value: number | null;
264
+ }
265
+
266
+ /**
267
+ * Weights, targets and trades for a valued portfolio, with its cash: the
268
+ * broker account's when it reports one, else the amount entered by hand.
269
+ */
270
+ export async function valuePortfolioAllocation({
271
+ valuation,
272
+ portfolio,
273
+ account,
274
+ toBase,
275
+ }: {
276
+ valuation: Pick<PortfolioValuation, "holdings">;
277
+ portfolio: Portfolio;
278
+ account?: BrokerAccount | null;
279
+ toBase: (value: number, fromCurrency: string) => Promise<number>;
280
+ }): Promise<{ allocation: PortfolioAllocation; cash: PortfolioCashReport | null }> {
281
+ const line = resolvePortfolioCash(portfolio, account);
282
+ const value = line && line.currency ? await toBase(line.amount, line.currency) : null;
283
+ const cash = line ? { amount: line.amount, currency: line.currency, source: line.source, value: value != null && Number.isFinite(value) ? value : null } : null;
284
+ const allocation = buildPortfolioAllocation({
285
+ holdings: valuation.holdings,
286
+ cashValue: cash ? cash.value ?? Number.NaN : null,
287
+ targets: portfolio.targetWeights,
288
+ });
289
+ return { allocation, cash };
227
290
  }
228
291
 
292
+ /** Colors a signed figure only when its text shows a nonzero digit. */
293
+ function signed(text: string, value: number | null | undefined): string {
294
+ return /[1-9]/.test(text) ? colorBySign(text, value) : text;
295
+ }
296
+
297
+ const NOT_AVAILABLE = "n/a";
298
+
229
299
  async function showCollectionWithMarketData(
230
300
  name: string,
231
301
  ctx: CliCommandContext,
232
- { config, store, dataProvider }: MarketContext,
302
+ { config, store, dataProvider, persistence }: MarketContext,
233
303
  ) {
234
304
  const tickers = (await store.loadAllTickers()).sort((left, right) =>
235
305
  left.metadata.ticker.localeCompare(right.metadata.ticker)
@@ -254,14 +324,22 @@ async function showCollectionWithMarketData(
254
324
  // A portfolio reports in its own currency, as its pane totals; a watchlist in the base currency.
255
325
  const currency = resolvePortfolioTotalsCurrency(matchedPortfolio, config.baseCurrency);
256
326
  const toBase = createBaseConverter(dataProvider, currency);
327
+ const account = matchedPortfolio ? findCachedPortfolioAccount(config, matchedPortfolio, persistence?.resources) : null;
328
+ const hasCash = !!resolvePortfolioCash(matchedPortfolio, account) || hasTargetWeights(matchedPortfolio);
257
329
 
258
- if (filtered.length === 0 && !structured) {
330
+ if (filtered.length === 0 && !structured && !hasCash) {
259
331
  console.log(cliStyles.bold(displayName));
260
332
  console.log(cliStyles.muted("No tickers in this collection."));
261
333
  return;
262
334
  }
263
335
 
264
336
  const quotes = await loadCollectionQuotes(filtered, collection, dataProvider);
337
+ // Worst of across the holdings' quotes, as the PORT and watchlist reports state it.
338
+ const broker = !!(matchedPortfolio?.brokerId || matchedPortfolio?.brokerInstanceId);
339
+ const freshness = quotesFreshness(quotes.values(), {
340
+ source: !isPortfolio ? "Local watchlist and Gloom Cloud"
341
+ : broker ? "Your broker account and Gloom Cloud" : "Local portfolio and Gloom Cloud",
342
+ });
265
343
 
266
344
  if (!structured) {
267
345
  console.log(cliStyles.bold(displayName + (isPortfolio ? ` (${currency})` : "")));
@@ -269,7 +347,8 @@ async function showCollectionWithMarketData(
269
347
  console.log("");
270
348
  }
271
349
 
272
- if (isPortfolio) {
350
+ if (matchedPortfolio) {
351
+ const valuation = await valuePortfolioPositions({ tickers: filtered, quotes, portfolioId: id, currency, baseCurrency: config.baseCurrency, toBase });
273
352
  const {
274
353
  positions: valued,
275
354
  totalPnl,
@@ -277,56 +356,170 @@ async function showCollectionWithMarketData(
277
356
  unavailableCost,
278
357
  unavailableMarketValue,
279
358
  brokerPnlSymbols,
280
- } = await valuePortfolioPositions({ tickers: filtered, quotes, portfolioId: id, currency, baseCurrency: config.baseCurrency, toBase });
281
- const positionsExport = valued.map((entry) => entry.row);
282
- const rows: string[][] = valued.map(({ ticker, quote, activeQuote, position, metrics, pnl }) => {
359
+ } = valuation;
360
+ const { allocation, cash } = await valuePortfolioAllocation({ valuation, portfolio: matchedPortfolio, account, toBase });
361
+ const allocationBySymbol = new Map(allocation.rows.map((row) => [row.symbol, row]));
362
+ const showTargets = allocation.targetSum != null;
363
+ // A ticker held in several lots carries its allocation on its first row.
364
+ const firstRows = new Set<string>();
365
+ const positionsExport = valued.map((entry): Record<string, unknown> & {
366
+ weight: number | null; targetWeight: number | null; drift: number | null; tradeShares: number | null; tradeValue: number | null;
367
+ } => {
368
+ const symbol = entry.ticker.metadata.ticker;
369
+ const first = !firstRows.has(symbol);
370
+ firstRows.add(symbol);
371
+ const figures = first ? allocationBySymbol.get(symbol) : undefined;
372
+ return {
373
+ ...entry.row,
374
+ weight: figures?.weight ?? null,
375
+ targetWeight: figures?.targetWeight ?? null,
376
+ drift: figures?.drift ?? null,
377
+ tradeShares: figures?.tradeUnits ?? null,
378
+ tradeValue: figures?.tradeValue ?? null,
379
+ };
380
+ });
381
+ const totalPnlValue = unavailablePnl.size > 0 ? null : totalPnl;
382
+ const cashExport = cash && allocation.cash ? {
383
+ ...cash,
384
+ weight: allocation.cash.weight,
385
+ targetWeight: allocation.cash.targetWeight,
386
+ drift: allocation.cash.drift,
387
+ tradeValue: allocation.cash.tradeValue,
388
+ } : allocation.cash ? {
389
+ amount: 0, currency, source: "manual" as const, value: 0,
390
+ weight: allocation.cash.weight, targetWeight: allocation.cash.targetWeight,
391
+ drift: allocation.cash.drift, tradeValue: allocation.cash.tradeValue,
392
+ } : null;
393
+
394
+ const accountingBasis = "Unrealized P&L on current positions; excludes realized trades, distributions and cash flows. This is not account investment return.";
395
+ const manualAccounting = !matchedPortfolio.brokerId && !matchedPortfolio.brokerInstanceId
396
+ ? "Manual holdings are snapshots. Reconcile shares and per-share cost after corporate actions using portfolio position set; cash distributions are not credited."
397
+ : null;
398
+ if (structured) {
399
+ // CSV and NDJSON read the cash and the total as rows; JSON keeps them in the metadata.
400
+ const extraRows: Record<string, unknown>[] = [
401
+ ...(cashExport ? [{ symbol: CASH_SYMBOL, marketValue: cashExport.value, baseCurrency: currency, weight: cashExport.weight,
402
+ targetWeight: cashExport.targetWeight, drift: cashExport.drift, tradeShares: null, tradeValue: cashExport.tradeValue }] : []),
403
+ { symbol: "TOTAL", marketValue: allocation.total, unrealizedPnl: totalPnlValue, baseCurrency: currency,
404
+ weight: allocation.total != null && allocation.total > 0 ? 100 : null, targetWeight: allocation.targetSum },
405
+ ];
406
+ ctx.printResult({ data: positionsExport, metadata: {
407
+ portfolioId: id, portfolioName: displayName, baseCurrency: currency, currency,
408
+ total: allocation.total, cash: cashExport, targetSum: allocation.targetSum,
409
+ unpricedCount: allocation.unpriced.length, unpricedSymbols: allocation.unpriced,
410
+ totalUnrealizedPnl: totalPnlValue,
411
+ complete: unavailablePnl.size === 0 && unavailableCost.size === 0 && unavailableMarketValue.size === 0,
412
+ unavailableSymbols: [...new Set([...unavailablePnl, ...unavailableCost, ...unavailableMarketValue])],
413
+ unavailableCostSymbols: [...unavailableCost], brokerPnlSymbols: [...brokerPnlSymbols],
414
+ accountingBasis, ...(manualAccounting ? { manualAccounting } : {}),
415
+ }, freshness }, { rows: (data) => [...(data as Record<string, unknown>[]), ...extraRows] });
416
+ return;
417
+ }
418
+
419
+ const money = (value: number | null | undefined, options?: { signed?: boolean }) => formatAllocationMoney(value, currency, options);
420
+ // Values and trades in whole units keep the table inside 80 columns; prices, costs and P&L keep the minor unit.
421
+ const wholeMoney = (value: number | null | undefined, options?: { signed?: boolean }) => formatAllocationMoney(value, currency, { ...options, whole: true });
422
+ const allocationCells = (
423
+ figures: { weight: number | null; targetWeight: number | null; drift: number | null; tradeValue: number | null; tradeUnits?: number | null } | undefined,
424
+ { unpriced, units, assetCategory }: { unpriced: boolean; units?: number; assetCategory?: string },
425
+ ): string[] => {
426
+ const missing = unpriced ? NOT_AVAILABLE : "—";
427
+ const weight = figures?.weight != null ? formatAllocationWeight(figures.weight) : missing;
428
+ if (!showTargets) return [weight];
429
+ const target = figures?.targetWeight != null ? formatAllocationWeight(figures.targetWeight) : "—";
430
+ const hasTarget = figures?.targetWeight != null;
431
+ const drift = figures?.drift != null ? signed(formatAllocationDrift(figures.drift), figures.drift) : hasTarget ? missing : "—";
432
+ const trade = units == null ? "" : figures?.tradeUnits != null
433
+ ? signed(formatTradeUnits(figures.tradeUnits, { units, assetCategory }), figures.tradeUnits)
434
+ : hasTarget ? missing : "—";
435
+ const tradeValue = figures?.tradeValue != null ? signed(wholeMoney(figures.tradeValue, { signed: true }), figures.tradeValue) : hasTarget ? missing : "—";
436
+ return [weight, target, drift, trade, tradeValue];
437
+ };
438
+
439
+ const rows: string[][] = valued.map(({ ticker, quote, activeQuote, position, metrics, pnl, row }, index) => {
283
440
  const priceText = quote && activeQuote
284
441
  ? colorBySign(formatMarketPriceWithCurrency(activeQuote.price, quote.currency, priceFormatOptions(quote, ticker.metadata.assetCategory)), activeQuote.change)
285
442
  : "—";
286
443
  const changeText = activeQuote ? colorBySign(formatPercentRaw(activeQuote.changePercent), activeQuote.change) : "—";
287
- if (!position || !metrics) return [ticker.metadata.ticker, priceText, changeText, "—", "—", "—"];
444
+ const exported = positionsExport[index]!;
445
+ const figures = exported.weight != null || exported.targetWeight != null || exported.tradeValue != null
446
+ ? { weight: exported.weight, targetWeight: exported.targetWeight, drift: exported.drift, tradeValue: exported.tradeValue, tradeUnits: exported.tradeShares }
447
+ : undefined;
448
+ const symbolUnits = allocationBySymbol.get(ticker.metadata.ticker)?.units ?? 0;
449
+ if (!position || !metrics) {
450
+ return [ticker.metadata.ticker, priceText, changeText, "—", "—", "—",
451
+ ...allocationCells(figures, { unpriced: false, units: symbolUnits, assetCategory: ticker.metadata.assetCategory }), "—"];
452
+ }
288
453
  const positionCurrency = metrics.positionCurrency;
454
+ const marketValue = row.marketValue as number | null;
455
+ const unpriced = marketValue == null;
289
456
  return [
290
457
  ticker.metadata.ticker,
291
458
  priceText,
292
459
  changeText,
293
460
  formatMarketQuantity(metrics.totalShares, { assetCategory: ticker.metadata.assetCategory, multiplier: position.multiplier, priceBasis: metrics.priceBasis, quantityCurrency: positionCurrency }),
294
461
  formatMarketCostWithCurrency(position.avgCost, positionCurrency, { assetCategory: ticker.metadata.assetCategory, multiplier: position.multiplier, priceBasis: metrics.priceBasis }),
295
- pnl == null || !Number.isFinite(pnl) ? "—" : colorBySign(formatSignedCurrency(pnl, currency), pnl),
462
+ unpriced ? NOT_AVAILABLE : wholeMoney(marketValue),
463
+ ...allocationCells(figures, { unpriced, units: symbolUnits, assetCategory: ticker.metadata.assetCategory }),
464
+ pnl == null || !Number.isFinite(pnl) ? "—" : colorBySign(money(pnl, { signed: true }), pnl),
296
465
  ];
297
466
  });
298
-
299
- const accountingBasis = "Unrealized P&L on current positions; excludes realized trades, distributions and cash flows. This is not account investment return.";
300
- const manualAccounting = !matchedPortfolio?.brokerId && !matchedPortfolio?.brokerInstanceId
301
- ? "Manual holdings are snapshots. Reconcile shares and per-share cost after corporate actions using portfolio position set; cash distributions are not credited."
302
- : null;
303
- if (structured) {
304
- ctx.printResult({ data: positionsExport, metadata: {
305
- portfolioId: id, portfolioName: displayName, baseCurrency: currency,
306
- totalUnrealizedPnl: unavailablePnl.size > 0 ? null : totalPnl,
307
- complete: unavailablePnl.size === 0 && unavailableCost.size === 0 && unavailableMarketValue.size === 0,
308
- unavailableSymbols: [...new Set([...unavailablePnl, ...unavailableCost, ...unavailableMarketValue])],
309
- unavailableCostSymbols: [...unavailableCost], brokerPnlSymbols: [...brokerPnlSymbols],
310
- accountingBasis, ...(manualAccounting ? { manualAccounting } : {}),
311
- } });
312
- return;
467
+ if (cashExport) {
468
+ const label = cashExport.currency && cashExport.currency !== currency ? `${CASH_SYMBOL} ${cashExport.currency}` : CASH_SYMBOL;
469
+ rows.push([label, "", "", "", "", cashExport.value == null ? NOT_AVAILABLE : wholeMoney(cashExport.value),
470
+ ...allocationCells(cashExport, { unpriced: cashExport.value == null }), ""]);
313
471
  }
472
+ const total = allocation.total;
473
+ rows.push([
474
+ cliStyles.bold("TOTAL"), "", "", "", "",
475
+ cliStyles.bold(wholeMoney(total)),
476
+ total != null && total > 0 ? formatAllocationWeight(100) : "—",
477
+ ...(showTargets ? [formatAllocationWeight(allocation.targetSum), "", "", ""] : []),
478
+ totalPnlValue == null ? "—" : colorBySign(money(totalPnlValue, { signed: true }), totalPnlValue),
479
+ ]);
314
480
 
481
+ const quantityHeader = filtered.some(ticker => ticker.metadata.assetCategory?.toUpperCase() === "BOND") || positionsExport.some(row => row.quantityUnit === "face") ? "Qty" : "Shares";
482
+ // A narrow terminal drops the cost, then the quote, then P&L, before any of the allocation.
315
483
  console.log(renderTable(
316
484
  [
317
485
  { header: "Ticker" },
318
- { header: "Last", align: "right" },
319
- { header: "Chg", align: "right" },
320
- { header: filtered.some(ticker => ticker.metadata.assetCategory?.toUpperCase() === "BOND") || positionsExport.some(row => row.quantityUnit === "face") ? "Qty" : "Shares", align: "right" },
321
- { header: "Avg Cost", align: "right" },
322
- { header: "P&L", align: "right" },
486
+ { header: "Last", align: "right", optional: true, dropPriority: 1 },
487
+ { header: "Chg", align: "right", optional: true, dropPriority: 2 },
488
+ { header: quantityHeader, align: "right" },
489
+ { header: "Avg Cost", align: "right", optional: true, dropPriority: 3 },
490
+ { header: "Value", align: "right" },
491
+ { header: "Weight", align: "right" },
492
+ ...(showTargets
493
+ ? [
494
+ { header: "Target", align: "right" as const },
495
+ { header: "Drift", align: "right" as const },
496
+ { header: "Trade", align: "right" as const },
497
+ { header: "Trade Value", align: "right" as const },
498
+ ]
499
+ : []),
500
+ { header: "P&L", align: "right", optional: true },
323
501
  ],
324
502
  rows,
325
503
  ));
326
504
  console.log("");
327
- console.log(renderStats([[brokerPnlSymbols.size ? "Total P&L (incl. broker snapshots)" : "Total P&L", unavailablePnl.size > 0 ? "—" : colorBySign(formatSignedCurrency(totalPnl, currency), totalPnl)]]));
328
- if (unavailableCost.size > 0) console.log(cliStyles.muted(`Cost unavailable for ${[...unavailableCost].join(", ")}.`));
329
- if (unavailablePnl.size > 0) console.log(cliStyles.muted(`P&L unavailable for ${[...unavailablePnl].join(", ")}.`));
505
+ const notes: string[] = [];
506
+ if (allocation.unpriced.length > 0) {
507
+ const count = allocation.unpriced.length;
508
+ notes.push(cliStyles.warning(`Total and weights exclude ${count} unpriced holding${count === 1 ? "" : "s"}: ${allocation.unpriced.join(", ")}.`));
509
+ }
510
+ if (cashExport?.source === "broker") notes.push(cliStyles.muted("Cash is the broker account's balance as of its last sync."));
511
+ if (matchedPortfolio.brokerInstanceId && !account) notes.push(cliStyles.warning(BROKER_ACCOUNT_MISSING_NOTE));
512
+ if (cashExport && cashExport.value == null) {
513
+ notes.push(cliStyles.warning(cashExport.currency
514
+ ? `No ${cashExport.currency}/${currency} rate for the cash, so the total and weights are unavailable.`
515
+ : "The cash's currency is unknown, so the total and weights are unavailable."));
516
+ }
517
+ const targetNote = describeTargetSum(allocation.targetSum);
518
+ if (targetNote) notes.push(cliStyles.muted(targetNote));
519
+ if (brokerPnlSymbols.size > 0) notes.push(cliStyles.muted(`P&L for ${[...brokerPnlSymbols].join(", ")} is the broker's last snapshot.`));
520
+ if (unavailableCost.size > 0) notes.push(cliStyles.muted(`Cost unavailable for ${[...unavailableCost].join(", ")}.`));
521
+ if (unavailablePnl.size > 0) notes.push(cliStyles.muted(`P&L unavailable for ${[...unavailablePnl].join(", ")}.`));
522
+ for (const note of notes) console.log(note);
330
523
  } else {
331
524
  const rows: string[][] = [];
332
525
  for (const ticker of filtered) {
@@ -359,5 +552,5 @@ async function showCollectionWithMarketData(
359
552
  rows,
360
553
  ));
361
554
  }
362
-
555
+ if (freshness) console.log(`\n${cliFreshnessFooter(freshness)}`);
363
556
  }
@@ -1,5 +1,32 @@
1
1
  import type { AppConfig } from "../../../../types/config";
2
+ import type { CliCommandContext } from "../../../../types/plugin";
3
+ import type { TickerRecord } from "../../../../types/ticker";
4
+ import { parseListingArg, type SavedListingName } from "../../../../cli/listing-arg";
5
+ import { isUsListingExchange } from "../../../../utils/exchanges";
2
6
  import { findPortfolio, isManualPortfolio } from "../mutations";
7
+ import { CASH_SYMBOL } from "../allocation";
8
+
9
+ /** A command error with a hint printed under it. */
10
+ export class PortfolioCliError extends Error {
11
+ constructor(message: string, readonly details?: string) {
12
+ super(message);
13
+ this.name = "PortfolioCliError";
14
+ }
15
+ }
16
+
17
+ /** Fails the command with the error's message and hint, or the fallback for anything unexpected. */
18
+ export function failPortfolioCommand(ctx: CliCommandContext, error: unknown, fallback: string): never {
19
+ if (error instanceof Error) {
20
+ const details = (error as { details?: unknown }).details;
21
+ return ctx.fail(error.message, typeof details === "string" ? details : undefined);
22
+ }
23
+ return ctx.fail(fallback);
24
+ }
25
+
26
+ /** What add and remove report about the listing they changed, as JSON and as the sentence's subject. */
27
+ export function listingFields(saved: SavedListingName) {
28
+ return { listing: saved.key, symbol: saved.symbol, exchange: saved.exchange || null, name: saved.name };
29
+ }
3
30
 
4
31
  export function parseFiniteNumber(rawValue: string | undefined, label: string): number {
5
32
  const value = Number(rawValue);
@@ -9,13 +36,51 @@ export function parseFiniteNumber(rawValue: string | undefined, label: string):
9
36
  return value;
10
37
  }
11
38
 
12
- export function requireManualPortfolio(config: AppConfig, rawName: string): NonNullable<ReturnType<typeof findPortfolio>> {
39
+ export function requirePortfolio(config: AppConfig, rawName: string): NonNullable<ReturnType<typeof findPortfolio>> {
13
40
  const portfolio = findPortfolio(config, rawName);
14
41
  if (!portfolio) {
15
- throw new Error(`Portfolio "${rawName}" was not found.`);
42
+ throw new PortfolioCliError(
43
+ `Portfolio "${rawName}" was not found.`,
44
+ config.portfolios.length > 0 ? `Portfolios: ${config.portfolios.map((entry) => entry.name).join(", ")}` : undefined,
45
+ );
16
46
  }
47
+ return portfolio;
48
+ }
49
+
50
+ export function requireManualPortfolio(config: AppConfig, rawName: string): NonNullable<ReturnType<typeof findPortfolio>> {
51
+ const portfolio = requirePortfolio(config, rawName);
17
52
  if (!isManualPortfolio(portfolio)) {
18
53
  throw new Error(`Portfolio "${portfolio.name}" is broker-managed and cannot be modified manually.`);
19
54
  }
20
55
  return portfolio;
21
56
  }
57
+
58
+ /** Whether the argument is the bare cash line rather than a listing (`CASH:NASDAQ` is a stock). */
59
+ export function isCashArgument(symbol: string, exchange?: string): boolean {
60
+ const listing = parseListingArg(symbol, exchange);
61
+ return listing.symbol === CASH_SYMBOL && !listing.exchange;
62
+ }
63
+
64
+ /**
65
+ * Bare `CASH` would resolve to a company that trades under that symbol and
66
+ * value the cash as its shares. Cash has its own line.
67
+ */
68
+ export function rejectCashSymbol(symbol: string, exchange: string | undefined, portfolioName: string): void {
69
+ if (!isCashArgument(symbol, exchange)) return;
70
+ throw new PortfolioCliError(
71
+ "CASH is the portfolio's cash line, not a ticker.",
72
+ `Record cash with: gloomberb portfolio cash set "${portfolioName}" <amount> [currency]. For the stock that trades as CASH, name its exchange: CASH:NASDAQ.`,
73
+ );
74
+ }
75
+
76
+ /** `VTI (Vanguard Total Stock Market ETF)`, with the venue and currency for a listing outside the US. */
77
+ export function describeTicker(ticker: TickerRecord): string {
78
+ const { ticker: symbol, name, exchange, currency } = ticker.metadata;
79
+ const foreign = !!exchange && !isUsListingExchange(exchange);
80
+ const details = [
81
+ name?.trim(),
82
+ foreign ? exchange : undefined,
83
+ foreign && currency && currency.toUpperCase() !== "USD" ? currency.toUpperCase() : undefined,
84
+ ].filter((part): part is string => !!part);
85
+ return details.length > 0 ? `${symbol} (${details.join(", ")})` : symbol;
86
+ }
@@ -3,6 +3,8 @@ import { withConfigData, withMarketData } from "../../../../cli/scoped-context";
3
3
  import { countCollectionTickers, findWatchlist } from "../../../../cli/helpers";
4
4
  import { slugifyName } from "../../../../utils/slugify";
5
5
  import { resolveTickerForCli } from "../../../../cli/ticker-resolution";
6
+ import { takeOption } from "../../../../cli/commands/command-utils";
7
+ import { EXCHANGE_OPTION, loadSavedListing, requireListingArg, savedListingName } from "../../../../cli/listing-arg";
6
8
  import {
7
9
  cliStyles,
8
10
  renderSection,
@@ -10,9 +12,13 @@ import {
10
12
  renderTable,
11
13
  } from "../../../../utils/cli-output";
12
14
  import type { CliCommandContext, CliCommandDef } from "../../../../types/plugin";
13
- import type { TickerRecord } from "../../../../types/ticker";
14
- import { addTickerToWatchlist, deleteWatchlist as deleteWatchlistConfig } from "../mutations";
15
+ import {
16
+ addTickerToWatchlist,
17
+ deleteWatchlist as deleteWatchlistConfig,
18
+ removeTickerFromWatchlist as removeWatchlistMembership,
19
+ } from "../mutations";
15
20
  import { showCollection } from "./render";
21
+ import { listingFields } from "./shared";
16
22
  import { CLI_COMMAND_GROUPS } from "../../../../cli/help";
17
23
 
18
24
  async function createWatchlist(name: string, ctx: CliCommandContext) {
@@ -52,52 +58,47 @@ async function deleteWatchlist(name: string, ctx: CliCommandContext) {
52
58
  });
53
59
  }
54
60
 
55
- async function addTickerToWatchlistCommand(watchlistName: string, symbol: string, ctx: CliCommandContext) {
61
+ async function addTickerToWatchlistCommand(watchlistName: string, symbol: string, exchange: string | undefined, ctx: CliCommandContext) {
56
62
  await withMarketData(ctx, async ({ config, store, dataProvider }) => {
57
63
  const watchlist = findWatchlist(config, watchlistName);
58
64
  if (!watchlist) ctx.fail(`Watchlist "${watchlistName}" was not found.`);
59
65
 
60
66
  try {
61
- const ticker = await resolveTickerForCli(symbol, store, dataProvider);
67
+ const ticker = await resolveTickerForCli(symbol, store, dataProvider, exchange);
62
68
  const result = addTickerToWatchlist(ticker, watchlist.id);
69
+ // Name the listing that was stored: SAN:EPA is not the SAN that a bare SAN means.
70
+ const saved = savedListingName(ticker);
71
+ const data = { changed: result.changed, ...listingFields(saved), watchlist: watchlist.name };
63
72
  if (!result.changed) {
64
- console.log(cliStyles.warning(`${ticker.metadata.ticker} is already in "${watchlist.name}".`));
73
+ ctx.printResult({ data }, { text: () => cliStyles.warning(`${saved.label} is already in "${watchlist.name}".`) });
65
74
  return;
66
75
  }
67
76
 
68
- const nextTicker = result.ticker;
69
- await store.saveTicker(nextTicker);
70
- console.log(cliStyles.success(`Added ${nextTicker.metadata.ticker} to "${watchlist.name}".`));
71
- if (nextTicker.metadata.name) {
72
- console.log(renderStats([["Name", nextTicker.metadata.name]]));
73
- }
77
+ await store.saveTicker(result.ticker);
78
+ ctx.printResult({ data }, { text: () => cliStyles.success(`Added ${saved.label} to "${watchlist.name}".`) });
74
79
  } catch (error) {
75
80
  ctx.fail(error instanceof Error ? error.message : `Failed to add ${symbol} to "${watchlist.name}".`);
76
81
  }
77
82
  });
78
83
  }
79
84
 
80
- async function removeTickerFromWatchlist(watchlistName: string, symbol: string, ctx: CliCommandContext) {
85
+ async function removeTickerFromWatchlist(watchlistName: string, symbol: string, exchange: string | undefined, ctx: CliCommandContext) {
86
+ // SAN:EPA and SAN --exchange EPA name the stored listing, which a bare SAN may hold under another venue.
87
+ const listing = await requireListingArg(symbol, exchange, ctx);
81
88
  await withConfigData(ctx, async ({ config, store }) => {
82
89
  const watchlist = findWatchlist(config, watchlistName);
83
90
  if (!watchlist) ctx.fail(`Watchlist "${watchlistName}" was not found.`);
84
91
 
85
- const normalized = symbol.trim().toUpperCase();
86
- const ticker = await store.loadTicker(normalized);
87
- if (!ticker) ctx.fail(`Ticker "${normalized}" was not found in your local data.`);
88
- if (!ticker.metadata.watchlists.includes(watchlist.id)) {
89
- ctx.fail(`${normalized} is not in "${watchlist.name}".`);
90
- }
92
+ const ticker = await loadSavedListing(store, listing);
93
+ if (!ticker) ctx.fail(`Ticker "${listing.key}" was not found in your local data.`);
94
+ const saved = savedListingName(ticker);
95
+ const result = removeWatchlistMembership(ticker, watchlist.id);
96
+ if (!result.changed) ctx.fail(`${saved.key} is not in "${watchlist.name}".`);
91
97
 
92
- const nextTicker: TickerRecord = {
93
- ...ticker,
94
- metadata: {
95
- ...ticker.metadata,
96
- watchlists: ticker.metadata.watchlists.filter((entry) => entry !== watchlist.id),
97
- },
98
- };
99
- await store.saveTicker(nextTicker);
100
- console.log(cliStyles.success(`Removed ${normalized} from "${watchlist.name}".`));
98
+ await store.saveTicker(result.ticker);
99
+ ctx.printResult({ data: { changed: true, ...listingFields(saved), watchlist: watchlist.name } }, {
100
+ text: () => cliStyles.success(`Removed ${saved.label} from "${watchlist.name}".`),
101
+ });
101
102
  });
102
103
  }
103
104
 
@@ -156,9 +157,12 @@ export const watchlistCliCommand: CliCommandDef = {
156
157
  "watchlist add <watchlist> <symbol>",
157
158
  "watchlist remove <watchlist> <symbol>",
158
159
  ],
159
- examples: ["watchlist show Growth", "watchlist create Growth", "watchlist add Growth NVDA"],
160
+ options: [EXCHANGE_OPTION],
161
+ examples: ["watchlist show Growth", "watchlist create Growth", "watchlist add Growth NVDA", "watchlist add Growth SAN:EPA"],
160
162
  },
161
- execute: async (args, ctx) => {
163
+ execute: async (rawArgs, ctx) => {
164
+ const args = [...rawArgs];
165
+ const exchange = takeOption(args, "--exchange");
162
166
  const action = args[0];
163
167
 
164
168
  if (!action || action === "list") {
@@ -191,7 +195,7 @@ export const watchlistCliCommand: CliCommandDef = {
191
195
  const symbol = args.at(-1);
192
196
  const name = args.slice(1, -1).join(" ");
193
197
  if (!name || !symbol) ctx.fail("Usage: gloomberb watchlist add <watchlist> <ticker>");
194
- await addTickerToWatchlistCommand(name!, symbol!, ctx);
198
+ await addTickerToWatchlistCommand(name!, symbol!, exchange, ctx);
195
199
  return;
196
200
  }
197
201
 
@@ -199,7 +203,7 @@ export const watchlistCliCommand: CliCommandDef = {
199
203
  const symbol = args.at(-1);
200
204
  const name = args.slice(1, -1).join(" ");
201
205
  if (!name || !symbol) ctx.fail("Usage: gloomberb watchlist remove <watchlist> <ticker>");
202
- await removeTickerFromWatchlist(name!, symbol!, ctx);
206
+ await removeTickerFromWatchlist(name!, symbol!, exchange, ctx);
203
207
  return;
204
208
  }
205
209