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
@@ -17,11 +17,14 @@ import {
17
17
  formatMarketPriceWithCurrency,
18
18
  formatMarketQuantity,
19
19
  formatSignedMarketPrice,
20
+ withCurrencyMinorDigits,
20
21
  withStablePriceDigits,
21
22
  type MarketFormatOptions,
22
23
  } from "../../../market-data/market/format";
23
24
  import {
24
25
  getActiveQuoteDisplay,
26
+ getCompletedRegularSessionDisplay,
27
+ getExtendedSessionDisplay,
25
28
  marketChangeColor,
26
29
  marketPriceColor,
27
30
  marketStateDot,
@@ -48,6 +51,14 @@ import {
48
51
  type PortfolioPositionPnl,
49
52
  } from "./position-metrics";
50
53
  import { isFiniteNumber } from "../../../utils/guards";
54
+ import {
55
+ allocationFigures,
56
+ formatAllocationDrift,
57
+ formatAllocationWeight,
58
+ formatTradeUnits,
59
+ holdingTarget,
60
+ type AllocationFigures,
61
+ } from "./allocation";
51
62
 
52
63
  export interface ColumnContext {
53
64
  activeTab?: string;
@@ -56,8 +67,14 @@ export interface ColumnContext {
56
67
  exchangeRates: Map<string, number>;
57
68
  /** Clock for quote age (per second while shown) and day-based columns. */
58
69
  now: number;
59
- /** Gross market value of the collection; weights may trail it by about a second. */
70
+ /**
71
+ * The total a portfolio's weights divide by: its priced holdings at net
72
+ * market value plus its cash (see allocation.ts). It may trail the rows by
73
+ * about a second.
74
+ */
60
75
  portfolioTotalMarketValue?: number;
76
+ /** The portfolio's target weights in percent, by symbol. */
77
+ portfolioTargets?: Readonly<Record<string, number>>;
61
78
  supplementalVersion?: number;
62
79
  analystResearch?: Map<string, AnalystResearchData | null>;
63
80
  corporateActions?: Map<string, CorporateActionsData | null>;
@@ -169,19 +186,61 @@ function tradedQuoteDisplay(
169
186
  return valuation && metrics.valuesAtMark ? getActiveQuoteDisplay(quote) : valuation;
170
187
  }
171
188
 
189
+ /**
190
+ * LAST, CHG and CHG% once the regular session is over, and in the pre-market
191
+ * while the quote carries the last session's close and move: that close and its
192
+ * move, frozen, because the EXT% column carries the extended print measured
193
+ * from that close. Until the close, and wherever no close is reported (a
194
+ * pre-market quote without it, venues without extended hours), the traded price
195
+ * as above.
196
+ * Valuation columns (DAY P&L, MKT VAL, weight, P&L) keep the live price.
197
+ * A watchlist's Avg Day averages this CHG%.
198
+ */
199
+ export function headlineQuoteDisplay(
200
+ traded: ActiveQuoteDisplay | null,
201
+ quote: TickerFinancials["quote"],
202
+ ): ActiveQuoteDisplay | null {
203
+ return traded ? getCompletedRegularSessionDisplay(quote) ?? traded : null;
204
+ }
205
+
206
+ /** CHG% as shown: the headline's, else the quote's own when no position price is usable. */
207
+ function headlineChangePercent(
208
+ headline: ActiveQuoteDisplay | null,
209
+ quote: TickerFinancials["quote"],
210
+ ): number | undefined {
211
+ if (headline) return headline.changePercent;
212
+ return quote ? (getCompletedRegularSessionDisplay(quote) ?? quote).changePercent : undefined;
213
+ }
214
+
172
215
  function fiftyTwoWeekPosition(displayQuote: ActiveQuoteDisplay | null, quote: TickerFinancials["quote"]): number | null {
173
216
  const range = displayQuote ? liveFiftyTwoWeekRange(quote, displayQuote.price) : null;
174
217
  return displayQuote && range ? ((displayQuote.price - range.low) / (range.high - range.low)) * 100 : null;
175
218
  }
176
219
 
177
- function getActiveMarketValue(
220
+ /** The row's weight, target, drift and trade, from its own live value and the pane's total. */
221
+ function rowAllocation(
222
+ ticker: TickerRecord,
178
223
  activeQuote: ActiveQuoteDisplay | null,
179
- positionMetrics: ReturnType<typeof getPortfolioPositionMetrics>,
224
+ baseMetrics: ReturnType<typeof getPortfolioPositionMetrics>,
180
225
  toBaseQuote: (value: number) => number,
181
- ): number | null {
182
- return resolvePortfolioMarketValue(positionMetrics, activeQuote ? toBaseQuote(activeQuote.price) : null)?.gross ?? null;
226
+ ctx: ColumnContext,
227
+ ): AllocationFigures & { unpriced: boolean } {
228
+ const held = baseMetrics.positionCount > 0;
229
+ const unitPrice = activeQuote ? toBaseQuote(activeQuote.price) : null;
230
+ const marketValue = held ? resolvePortfolioMarketValue(baseMetrics, unitPrice)?.net ?? null : 0;
231
+ return {
232
+ ...allocationFigures(
233
+ { held, marketValue, units: baseMetrics.totalShares, unitPrice },
234
+ ctx.portfolioTotalMarketValue,
235
+ holdingTarget(ctx.portfolioTargets, ticker.metadata.ticker),
236
+ ),
237
+ unpriced: held && marketValue == null,
238
+ };
183
239
  }
184
240
 
241
+ /** A held position without a price says so where its allocation would be. */
242
+ const UNPRICED = "n/a";
243
+
185
244
  export function resolvePortfolioPriceValue(
186
245
  activeQuote: ActiveQuoteDisplay | null,
187
246
  brokerMarkPrice: number | undefined,
@@ -215,6 +274,7 @@ export function getColumnValue(
215
274
  const positionMetrics = getPortfolioPositionMetrics(ticker, ctx.activeTab, quoteCurrency, undefined, quote);
216
275
  const activeQuote = getPortfolioQuoteDisplay(positionMetrics, quote);
217
276
  const displayQuote = tradedQuoteDisplay(positionMetrics, activeQuote, quote);
277
+ const headlineQuote = headlineQuoteDisplay(displayQuote, quote);
218
278
  const { positionCurrency, totalShares, totalCost, totalCostUnits, totalPriceUnits, multiplierHint, brokerMarkPrice } = positionMetrics;
219
279
  const baseMetrics = getPortfolioPositionMetrics(ticker, ctx.activeTab, quoteCurrency, {
220
280
  currency: ctx.baseCurrency,
@@ -270,12 +330,12 @@ export function getColumnValue(
270
330
  case "tags":
271
331
  return { text: ticker.metadata.tags.length > 0 ? ticker.metadata.tags.join(",") : "—" };
272
332
  case "price":
273
- return resolvePortfolioPriceValue(displayQuote, brokerMarkPrice, displayQuote ? currentQuoteOptions : markOptions, col.width, quote?.marketState);
333
+ return resolvePortfolioPriceValue(headlineQuote, brokerMarkPrice, headlineQuote ? currentQuoteOptions : markOptions, col.width, quote?.marketState);
274
334
  case "change":
275
- if (!displayQuote) return { text: "—" };
335
+ if (!headlineQuote) return { text: "—" };
276
336
  return {
277
- text: formatSignedMarketPrice(displayQuote.change, { ...currentQuoteOptions, maxWidth: col.width }),
278
- color: marketChangeColor(displayQuote.change, quote?.marketState),
337
+ text: formatSignedMarketPrice(headlineQuote.change, { ...currentQuoteOptions, maxWidth: col.width }),
338
+ color: marketChangeColor(headlineQuote.change, quote?.marketState),
279
339
  };
280
340
  case "bid":
281
341
  return { text: quote?.bid != null ? formatMarketPrice(quote.bid, { ...currentQuoteOptions, maxWidth: col.width }) : "—" };
@@ -297,10 +357,12 @@ export function getColumnValue(
297
357
  if (!isFiniteNumber(quote?.bidSize) && !isFiniteNumber(quote?.askSize)) return { text: "—" };
298
358
  return { text: `${formatCompact(quote?.bidSize)}/${formatCompact(quote?.askSize)}` };
299
359
  }
300
- case "change_pct":
301
- return displayQuote
302
- ? { text: formatPercentRaw(displayQuote.changePercent), color: marketChangeColor(displayQuote.changePercent, quote?.marketState) }
303
- : { text: quote ? formatPercentRaw(quote.changePercent) : "—", color: quote ? marketChangeColor(quote.changePercent, quote.marketState) : undefined };
360
+ case "change_pct": {
361
+ const changePercent = headlineChangePercent(headlineQuote, quote);
362
+ return quote
363
+ ? { text: formatPercentRaw(changePercent), color: marketChangeColor(changePercent, quote.marketState) }
364
+ : { text: "—" };
365
+ }
304
366
  case "volume":
305
367
  return { text: isFiniteNumber(quote?.volume) ? formatCompact(quote.volume, { fixedDecimals: true }) : "—" };
306
368
  case "dollar_volume": {
@@ -324,34 +386,50 @@ export function getColumnValue(
324
386
  const dividendYield = liveDividendYield(quote, fundamentals);
325
387
  return { text: dividendYield != null ? `${(dividendYield * 100).toFixed(2)}%` : "—" };
326
388
  }
327
- case "ext_hours":
328
- if ((quote?.marketState === "PRE" || quote?.marketState === "PREPRE") && quote.preMarketPrice != null) {
329
- const changePercent = quote.preMarketChangePercent;
330
- if (!isFiniteNumber(changePercent)) return { text: "—" };
331
- return { text: formatPercentRaw(changePercent), color: priceColor(changePercent) };
332
- }
333
- if ((quote?.marketState === "POST" || quote?.marketState === "POSTPOST") && quote.postMarketPrice != null) {
334
- const changePercent = quote.postMarketChangePercent;
335
- if (!isFiniteNumber(changePercent)) return { text: "—" };
336
- return { text: formatPercentRaw(changePercent), color: priceColor(changePercent) };
337
- }
338
- return { text: "—" };
389
+ case "ext_hours": {
390
+ const changePercent = getExtendedSessionDisplay(quote)?.changePercent;
391
+ if (!isFiniteNumber(changePercent)) return { text: "—" };
392
+ return { text: formatPercentRaw(changePercent), color: priceColor(changePercent) };
393
+ }
339
394
  case "side":
340
395
  return { text: positionSideLabel(ticker, ctx.activeTab) ?? "—" };
341
396
  case "shares":
342
397
  return { text: positionMetrics.positionCount > 0 ? formatMarketQuantity(totalShares, { ...formatOptions, maxWidth: col.width }) : "—" };
343
398
  case "avg_cost":
344
399
  if (totalCostUnits === 0 || !Number.isFinite(totalCost)) return { text: "—" };
345
- return { text: formatMarketCost(totalCost / Math.abs(totalCostUnits), { ...formatOptions, maxWidth: col.width }) };
400
+ // A money cost keeps its currency's minor unit, as `portfolio show` prints it: 45.50, not 45.5.
401
+ return { text: formatMarketCost(totalCost / Math.abs(totalCostUnits), { ...withCurrencyMinorDigits(formatOptions, positionCurrency), maxWidth: col.width }) };
346
402
  case "cost_basis":
347
403
  if (baseMetrics.positionCount === 0 || !Number.isFinite(baseMetrics.totalCost)) return { text: "—" };
348
404
  return { text: formatCompact(baseMetrics.totalCost) };
349
- case "mkt_value":
350
- return { text: formatCompactAmount(resolvePortfolioMarketValue(baseMetrics, activeQuote ? toBaseQuote(activeQuote.price) : null)?.gross ?? Number.NaN) };
405
+ case "mkt_value": {
406
+ if (baseMetrics.positionCount === 0) return { text: "—" };
407
+ const marketValue = resolvePortfolioMarketValue(baseMetrics, activeQuote ? toBaseQuote(activeQuote.price) : null)?.gross;
408
+ return { text: marketValue == null ? UNPRICED : formatCompactAmount(marketValue) };
409
+ }
351
410
  case "weight": {
352
- const marketValue = getActiveMarketValue(activeQuote, baseMetrics, toBaseQuote);
353
- if (marketValue == null || !ctx.portfolioTotalMarketValue) return { text: "—" };
354
- return { text: formatPercentRaw((marketValue / ctx.portfolioTotalMarketValue) * 100) };
411
+ const allocation = rowAllocation(ticker, activeQuote, baseMetrics, toBaseQuote, ctx);
412
+ return { text: allocation.unpriced ? UNPRICED : formatAllocationWeight(allocation.weight) };
413
+ }
414
+ case "target_weight":
415
+ return { text: formatAllocationWeight(holdingTarget(ctx.portfolioTargets, ticker.metadata.ticker)) };
416
+ case "drift": {
417
+ const allocation = rowAllocation(ticker, activeQuote, baseMetrics, toBaseQuote, ctx);
418
+ if (allocation.unpriced && allocation.targetWeight != null) return { text: UNPRICED };
419
+ const text = formatAllocationDrift(allocation.drift);
420
+ return { text, color: /[1-9]/.test(text) ? priceColor(allocation.drift!) : undefined };
421
+ }
422
+ case "trade": {
423
+ const allocation = rowAllocation(ticker, activeQuote, baseMetrics, toBaseQuote, ctx);
424
+ if (allocation.unpriced && allocation.targetWeight != null) return { text: UNPRICED };
425
+ const text = formatTradeUnits(allocation.tradeUnits, { units: totalShares, assetCategory: ticker.metadata.assetCategory });
426
+ return { text, color: /[1-9]/.test(text) ? priceColor(allocation.tradeUnits!) : undefined };
427
+ }
428
+ case "trade_value": {
429
+ const allocation = rowAllocation(ticker, activeQuote, baseMetrics, toBaseQuote, ctx);
430
+ if (allocation.unpriced && allocation.targetWeight != null) return { text: UNPRICED };
431
+ const text = formatCompactAmount(allocation.tradeValue ?? undefined, { signed: true });
432
+ return { text, color: /[1-9]/.test(text) ? priceColor(allocation.tradeValue!) : undefined };
355
433
  }
356
434
  case "day_pnl":
357
435
  if (activeQuote && isFiniteNumber(activeQuote.change) && Number.isFinite(positionMetrics.grossPriceUnits) && positionMetrics.grossPriceUnits !== 0) {
@@ -438,6 +516,7 @@ export function getSortValue(
438
516
  const positionMetrics = getPortfolioPositionMetrics(ticker, ctx.activeTab, quoteCurrency, undefined, quote);
439
517
  const activeQuote = getPortfolioQuoteDisplay(positionMetrics, quote);
440
518
  const displayQuote = tradedQuoteDisplay(positionMetrics, activeQuote, quote);
519
+ const headlineQuote = headlineQuoteDisplay(displayQuote, quote);
441
520
  const { positionCurrency, totalShares, totalCost, totalCostUnits, totalPriceUnits, brokerMarkPrice } = positionMetrics;
442
521
  const baseMetrics = getPortfolioPositionMetrics(ticker, ctx.activeTab, quoteCurrency, {
443
522
  currency: ctx.baseCurrency,
@@ -471,7 +550,7 @@ export function getSortValue(
471
550
  case "tags":
472
551
  return ticker.metadata.tags.join(",");
473
552
  case "price":
474
- if (displayQuote) return displayQuote.price;
553
+ if (headlineQuote) return headlineQuote.price;
475
554
  if (brokerMarkPrice != null) return brokerMarkPrice;
476
555
  return null;
477
556
  case "bid":
@@ -490,9 +569,9 @@ export function getSortValue(
490
569
  ? (quote?.bidSize ?? 0) + (quote?.askSize ?? 0)
491
570
  : null;
492
571
  case "change":
493
- return displayQuote?.change ?? null;
572
+ return headlineQuote?.change ?? null;
494
573
  case "change_pct":
495
- return displayQuote?.changePercent ?? null;
574
+ return headlineChangePercent(headlineQuote, quote) ?? null;
496
575
  case "volume":
497
576
  return quote?.volume ?? null;
498
577
  case "dollar_volume":
@@ -512,13 +591,7 @@ export function getSortValue(
512
591
  case "dividend_yield":
513
592
  return liveDividendYield(quote, fundamentals) ?? null;
514
593
  case "ext_hours":
515
- if ((quote?.marketState === "PRE" || quote?.marketState === "PREPRE") && quote.preMarketPrice != null) {
516
- return quote.preMarketChangePercent ?? null;
517
- }
518
- if ((quote?.marketState === "POST" || quote?.marketState === "POSTPOST") && quote.postMarketPrice != null) {
519
- return quote.postMarketChangePercent ?? null;
520
- }
521
- return null;
594
+ return getExtendedSessionDisplay(quote)?.changePercent ?? null;
522
595
  case "side":
523
596
  return positionSideLabel(ticker, ctx.activeTab);
524
597
  case "shares":
@@ -529,12 +602,16 @@ export function getSortValue(
529
602
  return baseMetrics.positionCount > 0 && Number.isFinite(baseMetrics.totalCost) ? baseMetrics.totalCost : null;
530
603
  case "mkt_value":
531
604
  return resolvePortfolioMarketValue(baseMetrics, activeQuote ? toBaseQuote(activeQuote.price) : null)?.gross ?? null;
532
- case "weight": {
533
- const marketValue = getActiveMarketValue(activeQuote, baseMetrics, toBaseQuote);
534
- return marketValue != null && ctx.portfolioTotalMarketValue
535
- ? (marketValue / ctx.portfolioTotalMarketValue) * 100
536
- : null;
537
- }
605
+ case "weight":
606
+ return rowAllocation(ticker, activeQuote, baseMetrics, toBaseQuote, ctx).weight;
607
+ case "target_weight":
608
+ return holdingTarget(ctx.portfolioTargets, ticker.metadata.ticker) ?? null;
609
+ case "drift":
610
+ return rowAllocation(ticker, activeQuote, baseMetrics, toBaseQuote, ctx).drift;
611
+ case "trade":
612
+ return rowAllocation(ticker, activeQuote, baseMetrics, toBaseQuote, ctx).tradeUnits;
613
+ case "trade_value":
614
+ return rowAllocation(ticker, activeQuote, baseMetrics, toBaseQuote, ctx).tradeValue;
538
615
  case "day_pnl":
539
616
  if (activeQuote && isFiniteNumber(activeQuote.change) && Number.isFinite(positionMetrics.grossPriceUnits) && positionMetrics.grossPriceUnits !== 0) {
540
617
  return toBaseQuote(totalPriceUnits * activeQuote.change);
@@ -3,6 +3,7 @@ import type {
3
3
  HeadlessPaneColumn,
4
4
  HeadlessPaneContext,
5
5
  HeadlessPaneDefinition,
6
+ HeadlessPaneRow,
6
7
  HeadlessRowsResult,
7
8
  } from "../../../types/plugin";
8
9
  import type { TickerRecord } from "../../../types/ticker";
@@ -10,10 +11,21 @@ import { formatNumber, formatPercentRaw } from "../../../utils/format";
10
11
  import {
11
12
  findCollection,
12
13
  loadCollectionQuotes,
14
+ valuePortfolioAllocation,
13
15
  valuePortfolioPositions,
14
16
  type CollectionMatch,
15
17
  } from "./cli/render";
18
+ import {
19
+ BROKER_ACCOUNT_MISSING_NOTE,
20
+ CASH_SYMBOL,
21
+ describeTargetSum,
22
+ formatAllocationDrift,
23
+ formatAllocationWeight,
24
+ formatTradeUnits,
25
+ } from "./allocation";
26
+ import { currencyMinorDigits, formatMarketPrice, formatMarketQuantity } from "../../../market-data/market/format";
16
27
  import { resolvePortfolioTotalsCurrency } from "./summary/totals";
28
+ import { quoteFreshnessFields } from "../shared/report-freshness";
17
29
 
18
30
  const DEFAULT_ROW_LIMIT = 50;
19
31
  const MAX_ROW_LIMIT = 200;
@@ -21,22 +33,50 @@ const MAX_ROW_LIMIT = 200;
21
33
  const LISTED_COLLECTION_IDS = 12;
22
34
 
23
35
  const amount = (value: unknown) => formatNumber(typeof value === "number" ? value : undefined, 2);
36
+ /** Market values and trades in whole units, as `portfolio show` prints them. */
37
+ const wholeAmount = (value: unknown) => formatNumber(typeof value === "number" ? value : undefined, 0);
38
+ const signedAmount = (value: unknown) => (
39
+ typeof value === "number" && Number.isFinite(value) ? `${value > 0 && /[1-9]/.test(wholeAmount(value)) ? "+" : ""}${wholeAmount(value)}` : formatNumber(undefined)
40
+ );
24
41
  const percent = (value: unknown) => formatPercentRaw(typeof value === "number" ? value : undefined);
25
- const share = (value: unknown) => (
26
- typeof value === "number" && Number.isFinite(value) ? `${formatNumber(value, 2)}%` : formatNumber(undefined)
42
+ const weight = (value: unknown) => formatAllocationWeight(typeof value === "number" ? value : null);
43
+ const drift = (value: unknown) => formatAllocationDrift(typeof value === "number" ? value : null);
44
+ const quantity = (value: unknown, row: HeadlessPaneRow) => (
45
+ typeof value === "number" ? formatMarketQuantity(value, { assetCategory: textOf(row.assetCategory) }) : formatNumber(undefined)
46
+ );
47
+ const tradeUnits = (value: unknown, row: HeadlessPaneRow) => (
48
+ typeof value === "number" ? formatTradeUnits(value, { units: finite(row.shares) ?? 0, assetCategory: textOf(row.assetCategory) }) : formatNumber(undefined)
27
49
  );
50
+ /** Money per unit at the currency's minor digits: $230.00, not 230. */
51
+ const unitMoney = (currencyKey: string) => (value: unknown, row: HeadlessPaneRow) => (
52
+ typeof value === "number"
53
+ ? formatMarketPrice(value, { assetCategory: textOf(row.assetCategory), minimumFractionDigits: Math.min(2, currencyMinorDigits(textOf(row[currencyKey]))) })
54
+ : formatNumber(undefined)
55
+ );
56
+
57
+ function textOf(value: unknown): string | undefined {
58
+ return typeof value === "string" && value ? value : undefined;
59
+ }
28
60
 
29
61
  const POSITION_COLUMNS: HeadlessPaneColumn[] = [
30
62
  { key: "symbol", header: "Ticker" },
31
63
  { key: "name", header: "Name" },
32
- { key: "shares", header: "Qty", align: "right" },
33
- { key: "avgCost", header: "Avg Cost", align: "right", description: "Per unit, in the position's currency." },
34
- { key: "price", header: "Last", align: "right", description: "In the quote's currency." },
64
+ { key: "shares", header: "Qty", align: "right", format: quantity },
65
+ { key: "avgCost", header: "Avg Cost", align: "right", format: unitMoney("positionCurrency"), description: "Per unit, in the position's currency." },
66
+ { key: "price", header: "Last", align: "right", format: unitMoney("priceCurrency"), description: "In the quote's currency." },
35
67
  { key: "priceCurrency", header: "Ccy" },
36
68
  { key: "changePercent", header: "Chg", align: "right", format: percent },
37
- { key: "marketValue", header: "Mkt Val", align: "right", format: amount, description: "In the portfolio's currency; negative for shorts." },
69
+ { key: "marketValue", header: "Mkt Val", align: "right", format: wholeAmount, description: "In the portfolio's currency; negative for shorts." },
38
70
  { key: "unrealizedPnl", header: "P&L", align: "right", format: amount, description: "Unrealized, in the portfolio's currency." },
39
- { key: "weight", header: "Weight", align: "right", format: share, description: "Percent of the portfolio's gross market value." },
71
+ { key: "weight", header: "Weight", align: "right", format: weight, description: "Percent of the total value, cash included; unpriced holdings are left out." },
72
+ ];
73
+
74
+ /** Shown once the portfolio has a target weight. */
75
+ const TARGET_COLUMNS: HeadlessPaneColumn[] = [
76
+ { key: "targetWeight", header: "Target", align: "right", format: weight, description: "Target weight, in percent." },
77
+ { key: "drift", header: "Drift", align: "right", format: drift, description: "Weight minus target, in percentage points." },
78
+ { key: "tradeShares", header: "Trade", align: "right", format: tradeUnits, description: "Units to buy (+) or sell (-) to reach the target at the current price." },
79
+ { key: "tradeValue", header: "Trade Value", align: "right", format: signedAmount, description: "The trade in the portfolio's currency." },
40
80
  ];
41
81
 
42
82
  const WATCHLIST_COLUMNS: HeadlessPaneColumn[] = [
@@ -97,26 +137,36 @@ async function portfolioHoldings(
97
137
  const currency = resolvePortfolioTotalsCurrency(target.portfolio, ctx.config.baseCurrency);
98
138
  const quotes = await loadCollectionQuotes(tickers, target, ctx.marketData);
99
139
  ctx.signal.throwIfAborted();
140
+ const toBase = createBaseConverter(ctx.marketData, currency);
100
141
  const valuation = await valuePortfolioPositions({
101
142
  tickers,
102
143
  quotes,
103
144
  portfolioId: target.id,
104
145
  currency,
105
146
  baseCurrency: ctx.config.baseCurrency,
106
- toBase: createBaseConverter(ctx.marketData, currency),
147
+ toBase,
107
148
  });
149
+ const { allocation, cash } = await valuePortfolioAllocation({ valuation, portfolio: resolved.portfolio, account: resolved.account, toBase });
108
150
  ctx.signal.throwIfAborted();
109
151
 
152
+ const allocationBySymbol = new Map(allocation.rows.map((row) => [row.symbol, row]));
110
153
  const held = valuation.positions.filter((entry) => entry.position);
111
154
  const gross = held.reduce((sum, entry) => sum + Math.abs(finite(entry.row.marketValue) ?? 0), 0);
112
155
  const sum = (key: string) => held.reduce((total, entry) => total + (finite(entry.row[key]) ?? 0), 0);
156
+ const seen = new Set<string>();
113
157
  const rows = held
114
158
  .map(({ ticker, activeQuote, row }) => {
115
159
  const marketValue = finite(row.marketValue);
160
+ // A ticker held in several lots carries its allocation on its first row.
161
+ const figures = seen.has(ticker.metadata.ticker) ? undefined : allocationBySymbol.get(ticker.metadata.ticker);
162
+ seen.add(ticker.metadata.ticker);
116
163
  return {
164
+ ...quoteFreshnessFields(quotes.get(ticker.metadata.ticker)),
165
+ updatedAt: quotes.get(ticker.metadata.ticker)?.lastUpdated ?? null,
117
166
  symbol: ticker.metadata.ticker,
118
167
  name: ticker.metadata.name ?? null,
119
168
  exchange: ticker.metadata.exchange || null,
169
+ assetCategory: ticker.metadata.assetCategory ?? null,
120
170
  shares: finite(row.shares),
121
171
  avgCost: finite(row.avgCost),
122
172
  positionCurrency: row.positionCurrency ?? null,
@@ -125,7 +175,11 @@ async function portfolioHoldings(
125
175
  changePercent: finite(activeQuote?.changePercent),
126
176
  marketValue,
127
177
  unrealizedPnl: finite(row.unrealizedPnl),
128
- weight: marketValue != null && gross > 0 ? (Math.abs(marketValue) / gross) * 100 : null,
178
+ weight: figures?.weight ?? null,
179
+ targetWeight: figures?.targetWeight ?? null,
180
+ drift: figures?.drift ?? null,
181
+ tradeShares: figures?.tradeUnits ?? null,
182
+ tradeValue: figures?.tradeValue ?? null,
129
183
  };
130
184
  })
131
185
  // Largest exposure first; a position without a market value sorts last.
@@ -133,16 +187,40 @@ async function portfolioHoldings(
133
187
  exposure(right.marketValue) - exposure(left.marketValue)
134
188
  || left.symbol.localeCompare(right.symbol)
135
189
  ));
136
- const shown = rows.slice(0, limit);
190
+ const shown: HeadlessPaneRow[] = rows.slice(0, limit);
191
+ // The cash line follows the positions, whatever the limit.
192
+ if (allocation.cash) {
193
+ shown.push({
194
+ symbol: CASH_SYMBOL,
195
+ name: cash?.source === "broker" ? "Cash (broker account)" : "Cash",
196
+ priceCurrency: cash?.currency ?? null,
197
+ marketValue: finite(allocation.cash.value),
198
+ weight: allocation.cash.weight,
199
+ targetWeight: allocation.cash.targetWeight,
200
+ drift: allocation.cash.drift,
201
+ tradeShares: null,
202
+ tradeValue: allocation.cash.tradeValue,
203
+ });
204
+ }
137
205
  const unavailable = [...new Set([...valuation.unavailableMarketValue, ...valuation.unavailablePnl])];
138
206
  const broker = !!(target.portfolio.brokerId || target.portfolio.brokerInstanceId);
207
+ const showTargets = allocation.targetSum != null;
208
+ const targetNote = describeTargetSum(allocation.targetSum);
209
+ const notices = [
210
+ ...(rows.length > limit
211
+ ? [`${rows.length - limit} more position${rows.length - limit === 1 ? "" : "s"} not shown; totals include every position.`]
212
+ : []),
213
+ ...(targetNote ? [targetNote] : []),
214
+ ...(target.portfolio.brokerInstanceId && !resolved.account ? [BROKER_ACCOUNT_MISSING_NOTE] : []),
215
+ ];
139
216
 
140
217
  return {
141
- columns: POSITION_COLUMNS,
218
+ freshness: { source: broker ? "Your broker account and Gloom Cloud" : "Local portfolio and Gloom Cloud" },
219
+ columns: showTargets ? [...POSITION_COLUMNS, ...TARGET_COLUMNS] : POSITION_COLUMNS,
142
220
  rows: shown,
143
221
  complete: unavailable.length === 0,
144
222
  ...(unavailable.length
145
- ? { errors: [`No market value or P&L for ${unavailable.join(", ")}; totals leave them out.`] }
223
+ ? { errors: [`No market value or P&L for ${unavailable.join(", ")}; totals and weights leave them out.`] }
146
224
  : {}),
147
225
  metadata: {
148
226
  collection: { kind: "portfolio", id: target.id, name: target.name, broker },
@@ -153,10 +231,13 @@ async function portfolioHoldings(
153
231
  grossMarketValue: gross,
154
232
  costBasis: sum("costBasis"),
155
233
  unrealizedPnl: valuation.totalPnl,
234
+ cash: allocation.cash ? finite(allocation.cash.value) : null,
235
+ total: allocation.total,
156
236
  },
157
- ...(rows.length > shown.length
158
- ? { notices: [`${rows.length - shown.length} more position${rows.length - shown.length === 1 ? "" : "s"} not shown; totals include every position.`] }
159
- : {}),
237
+ ...(cash ? { cash } : {}),
238
+ ...(showTargets ? { targetSum: allocation.targetSum } : {}),
239
+ unpricedCount: allocation.unpriced.length,
240
+ ...(notices.length > 0 ? { notices } : {}),
160
241
  },
161
242
  };
162
243
  }
@@ -174,6 +255,8 @@ async function watchlistHoldings(
174
255
  const rows = tickers.map((ticker) => {
175
256
  const quote = quotes.get(ticker.metadata.ticker);
176
257
  return {
258
+ ...quoteFreshnessFields(quote),
259
+ updatedAt: quote?.lastUpdated ?? null,
177
260
  symbol: ticker.metadata.ticker,
178
261
  name: ticker.metadata.name ?? null,
179
262
  exchange: ticker.metadata.exchange || null,
@@ -184,6 +267,7 @@ async function watchlistHoldings(
184
267
  });
185
268
  const shown = rows.slice(0, limit);
186
269
  return {
270
+ freshness: { source: "Local watchlist and Gloom Cloud" },
187
271
  columns: WATCHLIST_COLUMNS,
188
272
  rows: shown,
189
273
  metadata: {
@@ -204,7 +288,7 @@ async function watchlistHoldings(
204
288
  export const collectionHoldingsHeadless: HeadlessPaneDefinition<"rows"> = {
205
289
  shape: "rows",
206
290
  description:
207
- "Positions held in a portfolio, broker or manual: symbol, quantity, average cost, last price, market value, unrealized P&L and weight, largest first, with totals. For a watchlist, its tickers with quotes. Takes a portfolio or watchlist ID; the first portfolio when omitted.",
291
+ "Positions held in a portfolio, broker or manual: symbol, quantity, average cost, last price, market value, unrealized P&L and weight of the total with cash, largest first, then the cash line and totals. With target weights set, each row adds its target, drift and the trade to reach it. For a watchlist, its tickers with quotes. Takes a portfolio or watchlist ID; the first portfolio when omitted.",
208
292
  discovery: {
209
293
  dataRequirements: ["Local portfolios, watchlists and synced broker positions; current quotes"],
210
294
  limitations: ["Unrealized P&L on current positions; excludes realized trades, distributions and cash flows"],
@@ -9,6 +9,7 @@ import {
9
9
  import { portfolioCliCommand } from "./cli/portfolio-command";
10
10
  import { watchlistCliCommand } from "./cli/watchlist-command";
11
11
  import { collectionHoldingsHeadless } from "./headless";
12
+ import { findCollection } from "./cli/render";
12
13
  import {
13
14
  LIVE_STREAMING_QUICK_SETTING,
14
15
  withLiveStreamingSetting,
@@ -30,8 +31,13 @@ function resolveCollectionIdForKind(context: PaneTemplateContext, kind: "portfol
30
31
  function createCollectionPaneInstance(
31
32
  context: PaneTemplateContext,
32
33
  kind?: "portfolio" | "watchlist",
34
+ argument?: string,
33
35
  ): PaneTemplateInstanceConfig | null {
34
- const collectionId = kind ? resolveCollectionIdForKind(context, kind) : resolveCollectionPaneId(context);
36
+ // `PF Retirement` (or `shot PF Retirement`) opens the collection it names.
37
+ const named = argument?.trim() ? findCollection(context.config, argument) : null;
38
+ const collectionId = named && (!kind || named.kind === kind)
39
+ ? named.id
40
+ : kind ? resolveCollectionIdForKind(context, kind) : resolveCollectionPaneId(context);
35
41
  return collectionId ? { params: { collectionId } } : null;
36
42
  }
37
43
 
@@ -39,6 +45,7 @@ export const portfolioListModule: PluginModule = {
39
45
  panes: [
40
46
  {
41
47
  id: "portfolio-list",
48
+ reportFreshness: { source: "Local portfolio and Gloom Cloud" },
42
49
  name: "Portfolio",
43
50
  icon: "P",
44
51
  component: PortfolioListPane,
@@ -75,11 +82,15 @@ export const portfolioListModule: PluginModule = {
75
82
  paneId: "portfolio-list",
76
83
  label: "Collection Pane",
77
84
  description: "Open another pane for the current portfolio or watchlist",
78
- keywords: ["portfolio", "watchlist", "collection", "pane", "list"],
85
+ // Phrases rather than bare words, so `fn rebalance` and `fn target` keep resolving where they did.
86
+ keywords: [
87
+ "portfolio", "watchlist", "collection", "pane", "list",
88
+ "portfolio rebalance", "allocation drift", "target weights", "asset allocation", "cash balance",
89
+ ],
79
90
  shortcut: { prefix: "PF" },
80
91
  headless: collectionHoldingsHeadless,
81
92
  canCreate: (context) => resolveCollectionPaneId(context) !== null,
82
- createInstance: (context) => createCollectionPaneInstance(context),
93
+ createInstance: (context, options) => createCollectionPaneInstance(context, undefined, options?.arg),
83
94
  },
84
95
  {
85
96
  id: "new-portfolio-pane",
@@ -1,6 +1,7 @@
1
1
  import type { AnalystResearchData, Fundamentals, Quote } from "../../../types/financials";
2
2
  import { hasLikelyQuoteUnitMismatch } from "../../../utils/currency-units";
3
3
  import { selectMarketCapitalization, type MarketCapitalization } from "../../../utils/market-capitalization";
4
+ import { priceEarningsOnEarnings, type PriceEarnings } from "../../../utils/price-earnings";
4
5
 
5
6
  /**
6
7
  * Price-derived statistics repriced from the current quote with the base
@@ -53,13 +54,14 @@ function repriceMultiple(
53
54
  return price / perShare;
54
55
  }
55
56
 
56
- /** Trailing P/E over the current price. Zero or negative EPS keeps the stored multiple. */
57
- export function liveTrailingPE(quote: Quote | null | undefined, fundamentals: Fundamentals | undefined): number | undefined {
58
- return repriceMultiple(fundamentals?.trailingPE, fundamentals?.eps, quote, fundamentals);
57
+ /** Trailing P/E over the current price; not meaningful when the trailing EPS is zero or a loss. */
58
+ export function liveTrailingPE(quote: Quote | null | undefined, fundamentals: Fundamentals | undefined): PriceEarnings | undefined {
59
+ return priceEarningsOnEarnings(repriceMultiple(fundamentals?.trailingPE, fundamentals?.eps, quote, fundamentals), fundamentals?.eps);
59
60
  }
60
61
 
61
- export function liveForwardPE(quote: Quote | null | undefined, fundamentals: Fundamentals | undefined): number | undefined {
62
- return repriceMultiple(fundamentals?.forwardPE, fundamentals?.forwardEps, quote, fundamentals);
62
+ /** Forward P/E over the current price; not meaningful when the forward EPS behind it is zero or a loss. */
63
+ export function liveForwardPE(quote: Quote | null | undefined, fundamentals: Fundamentals | undefined): PriceEarnings | undefined {
64
+ return priceEarningsOnEarnings(repriceMultiple(fundamentals?.forwardPE, fundamentals?.forwardEps, quote, fundamentals), fundamentals?.forwardEps);
63
65
  }
64
66
 
65
67
  /** Forward dividend yield over the current price, as a ratio like the stored yield. */