gloomberb 0.16.0 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (691) hide show
  1. package/README.md +2 -1
  2. package/package.json +2 -1
  3. package/src/api-client/beneficial-owners.ts +92 -0
  4. package/src/api-client/data.ts +44 -11
  5. package/src/api-client/errors.ts +12 -0
  6. package/src/api-client/geo.ts +363 -0
  7. package/src/api-client/index.ts +5 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/members.ts +26 -0
  10. package/src/api-client/paths.ts +30 -1
  11. package/src/api-client/perps.ts +41 -0
  12. package/src/api-client/request.ts +5 -2
  13. package/src/api-client/types.ts +9 -1
  14. package/src/app/global-shortcuts.ts +14 -6
  15. package/src/app/keybindings/actions.ts +1 -1
  16. package/src/app/runtime/update.ts +38 -2
  17. package/src/app.tsx +10 -6
  18. package/src/brokers/account-cache.ts +24 -0
  19. package/src/cli/commands/command-utils.ts +8 -0
  20. package/src/cli/commands/crypto-hints.ts +75 -0
  21. package/src/cli/commands/market.ts +414 -106
  22. package/src/cli/commands/overview.ts +77 -32
  23. package/src/cli/commands/ticker.ts +101 -43
  24. package/src/cli/desktop-pane-shot.ts +34 -4
  25. package/src/cli/freshness.ts +61 -0
  26. package/src/cli/help.ts +1 -0
  27. package/src/cli/helpers.ts +4 -8
  28. package/src/cli/index.ts +12 -2
  29. package/src/cli/listing-arg.ts +321 -0
  30. package/src/cli/pane-functions/access-gate.ts +42 -0
  31. package/src/cli/pane-functions/catalog.ts +28 -1
  32. package/src/cli/pane-functions/data.ts +3 -1
  33. package/src/cli/pane-functions/dom.ts +20 -2
  34. package/src/cli/pane-functions/freshness.ts +400 -0
  35. package/src/cli/pane-functions/function-help.ts +36 -22
  36. package/src/cli/pane-functions/headless.ts +39 -11
  37. package/src/cli/pane-functions/index.ts +15 -4
  38. package/src/cli/pane-functions/options.ts +3 -0
  39. package/src/cli/pane-functions/report.ts +4 -0
  40. package/src/cli/pane-functions/resolver.ts +35 -7
  41. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  42. package/src/cli/pane-functions/screenshot.ts +7 -3
  43. package/src/cli/result.ts +41 -27
  44. package/src/cli/ticker-resolution.ts +7 -5
  45. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  46. package/src/components/chart/composite/drawing-store.ts +59 -0
  47. package/src/components/chart/composite/legend.tsx +319 -0
  48. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  49. package/src/components/chart/composite/panel-gestures.ts +59 -0
  50. package/src/components/chart/composite/panel-labels.ts +107 -0
  51. package/src/components/chart/composite/panel-surface.tsx +876 -0
  52. package/src/components/chart/composite/tool-catalog.ts +98 -0
  53. package/src/components/chart/composite/toolbar.tsx +186 -0
  54. package/src/components/chart/composite/tools.ts +8 -0
  55. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  56. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  57. package/src/components/command-bar/commands/collection.ts +5 -1
  58. package/src/components/command-bar/list/model.ts +5 -0
  59. package/src/components/command-bar/list/view.tsx +16 -3
  60. package/src/components/command-bar/pane-templates/workflow.ts +1 -0
  61. package/src/components/command-bar/routes/root/command-items.ts +9 -2
  62. package/src/components/command-bar/routes/root/plugin-install.ts +2 -2
  63. package/src/components/command-bar/routes/root/provider-search.ts +19 -5
  64. package/src/components/command-bar/routes/root/runtime.ts +14 -5
  65. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  66. package/src/components/command-bar/routes/ticker-search/results.ts +31 -5
  67. package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
  68. package/src/components/command-bar/routing/actions.ts +2 -0
  69. package/src/components/command-bar/selection-runtime.ts +38 -0
  70. package/src/components/command-bar/surface/index.tsx +7 -2
  71. package/src/components/command-bar/workflow/ops.ts +1 -1
  72. package/src/components/command-bar/workflow/tickers.ts +6 -0
  73. package/src/components/data-table/view.tsx +29 -10
  74. package/src/components/feedback-dialog.tsx +2 -1
  75. package/src/components/form-modal/field-row.tsx +2 -2
  76. package/src/components/index.ts +2 -2
  77. package/src/components/layout/detached-pane-shell.tsx +6 -3
  78. package/src/components/layout/floating-pane.tsx +6 -0
  79. package/src/components/layout/header.tsx +24 -7
  80. package/src/components/layout/missing-pane.tsx +2 -2
  81. package/src/components/layout/pane/content.tsx +23 -10
  82. package/src/components/layout/pane/error-boundary.tsx +103 -0
  83. package/src/components/layout/pane/footer/registration.tsx +68 -23
  84. package/src/components/layout/pane/header.tsx +61 -28
  85. package/src/components/layout/pane/index.tsx +6 -0
  86. package/src/components/layout/pane/title.ts +31 -7
  87. package/src/components/layout/shell/drag/index.ts +6 -5
  88. package/src/components/layout/shell/drag/runtime.ts +3 -0
  89. package/src/components/layout/shell/index.tsx +6 -0
  90. package/src/components/layout/shell/menu.ts +2 -1
  91. package/src/components/layout/shell/pane/actions.ts +2 -1
  92. package/src/components/layout/shell/pane/layers.tsx +29 -10
  93. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -3
  94. package/src/components/layout/shell/ticker-link-menu.ts +23 -9
  95. package/src/components/metric-treemap/heat-surface.tsx +745 -0
  96. package/src/components/metric-treemap/heat-tiles.ts +228 -0
  97. package/src/components/metric-treemap/index.tsx +2 -0
  98. package/src/components/metric-treemap/layout.ts +8 -0
  99. package/src/components/metric-treemap/scene.ts +432 -0
  100. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  101. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  102. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  103. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  104. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  105. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -0
  106. package/src/components/ticker/list-table-view.tsx +13 -1
  107. package/src/components/toggle-list.tsx +38 -12
  108. package/src/components/ui/country-flag-art.tsx +449 -0
  109. package/src/components/ui/country-flag.tsx +41 -0
  110. package/src/components/ui/data-table/types.ts +13 -0
  111. package/src/components/ui/fields.tsx +8 -0
  112. package/src/components/ui/icon.tsx +2 -0
  113. package/src/components/ui/index.ts +4 -0
  114. package/src/components/ui/multi-select/dialog.tsx +108 -22
  115. package/src/components/ui/range-track.tsx +53 -0
  116. package/src/components/ui/status.tsx +8 -2
  117. package/src/components/ui/tabs.tsx +11 -4
  118. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  119. package/src/core/state/app/types.ts +10 -1
  120. package/src/data/config/store/normalize.ts +17 -1
  121. package/src/i18n/es.ts +24 -4
  122. package/src/i18n/ja.ts +24 -4
  123. package/src/i18n/ko.ts +24 -4
  124. package/src/i18n/zh-cn.ts +24 -4
  125. package/src/i18n/zh-tw.ts +24 -4
  126. package/src/layout/ticker-navigation.ts +28 -2
  127. package/src/market-data/coordinator/chart.ts +1 -1
  128. package/src/market-data/coordinator/quotes.ts +23 -4
  129. package/src/market-data/fx-closes.ts +72 -0
  130. package/src/market-data/market/freshness.ts +78 -6
  131. package/src/market-data/market/session-close-note.ts +57 -0
  132. package/src/market-data/market/status.ts +151 -0
  133. package/src/market-data/published-apac-sessions.ts +66 -0
  134. package/src/market-data/quotes/contributions.ts +8 -0
  135. package/src/market-data/quotes/freshness.ts +36 -0
  136. package/src/market-data/quotes/resolution.ts +24 -8
  137. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  138. package/src/market-data/quotes/time.ts +16 -0
  139. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  140. package/src/plugins/builtin/alerts/cli.ts +10 -5
  141. package/src/plugins/builtin/alerts/index.tsx +1 -0
  142. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  143. package/src/plugins/builtin/analytics/risk-client.ts +330 -79
  144. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  145. package/src/plugins/builtin/analytics/risk-headless.ts +61 -49
  146. package/src/plugins/builtin/analytics/risk-math.ts +33 -13
  147. package/src/plugins/builtin/analytics/risk-model.ts +282 -64
  148. package/src/plugins/builtin/analytics/risk-pane.tsx +62 -30
  149. package/src/plugins/builtin/analytics/risk-test-data.ts +206 -0
  150. package/src/plugins/builtin/attention/headless.ts +6 -4
  151. package/src/plugins/builtin/attention/index.tsx +1 -1
  152. package/src/plugins/builtin/attention/pane.tsx +1 -1
  153. package/src/plugins/builtin/awards/headless.ts +1 -0
  154. package/src/plugins/builtin/awards/pane.tsx +1 -1
  155. package/src/plugins/builtin/backtest/headless.ts +1 -0
  156. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  157. package/src/plugins/builtin/buildout/cells.tsx +15 -12
  158. package/src/plugins/builtin/buildout/detail/company.tsx +3 -3
  159. package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
  160. package/src/plugins/builtin/buildout/detail/intel.tsx +6 -6
  161. package/src/plugins/builtin/buildout/detail/site.tsx +4 -7
  162. package/src/plugins/builtin/buildout/detail/ui.tsx +0 -19
  163. package/src/plugins/builtin/buildout/index.tsx +1 -0
  164. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  165. package/src/plugins/builtin/catalysts/index.tsx +2 -2
  166. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  167. package/src/plugins/builtin/cds/headless.ts +2 -0
  168. package/src/plugins/builtin/cds/index.tsx +1 -0
  169. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  170. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  171. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  172. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  173. package/src/plugins/builtin/chat/channels.ts +19 -3
  174. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  175. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  176. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  177. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  178. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  179. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  180. package/src/plugins/builtin/chat/index.tsx +1 -0
  181. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  182. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  183. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  184. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  185. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  186. package/src/plugins/builtin/chat/message/types.ts +14 -2
  187. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  188. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  189. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  190. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  191. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  192. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  193. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  194. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  195. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  196. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  197. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  198. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  199. package/src/plugins/builtin/correlation/compute.ts +59 -16
  200. package/src/plugins/builtin/correlation/geo.ts +34 -0
  201. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  202. package/src/plugins/builtin/correlation/headless.ts +42 -8
  203. package/src/plugins/builtin/correlation/history.ts +2 -0
  204. package/src/plugins/builtin/correlation/index.tsx +68 -14
  205. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  206. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  207. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  208. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  209. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  210. package/src/plugins/builtin/correlation/settings.ts +1 -1
  211. package/src/plugins/builtin/cot/headless.ts +6 -3
  212. package/src/plugins/builtin/cot/index.tsx +3 -3
  213. package/src/plugins/builtin/cot/model.ts +36 -3
  214. package/src/plugins/builtin/cpi/headless.ts +4 -0
  215. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  216. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  217. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  218. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  219. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  220. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  221. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  222. package/src/plugins/builtin/debt-maturities/wall-bar.tsx +14 -41
  223. package/src/plugins/builtin/dividend-yield/client.ts +4 -2
  224. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  225. package/src/plugins/builtin/doe/headless.ts +7 -0
  226. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  227. package/src/plugins/builtin/earnings/client.ts +2 -2
  228. package/src/plugins/builtin/earnings/headless.ts +5 -0
  229. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  230. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  231. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  232. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  233. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  234. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  235. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  236. package/src/plugins/builtin/econ/index.tsx +1 -0
  237. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  238. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  239. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  240. package/src/plugins/builtin/executives/index.tsx +1 -0
  241. package/src/plugins/builtin/exposure/headless.ts +3 -1
  242. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  243. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  244. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  245. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  246. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  247. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  248. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  249. package/src/plugins/builtin/fx-matrix/direction.ts +81 -0
  250. package/src/plugins/builtin/fx-matrix/index.tsx +71 -33
  251. package/src/plugins/builtin/fx-matrix/live-legs.ts +17 -0
  252. package/src/plugins/builtin/fx-matrix/pairs.ts +68 -14
  253. package/src/plugins/builtin/fx-matrix/settings.ts +62 -0
  254. package/src/plugins/builtin/gpu/headless.ts +7 -3
  255. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  256. package/src/plugins/builtin/gpu/model.ts +27 -1
  257. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  258. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  259. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  260. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  261. package/src/plugins/builtin/holders/headless.ts +139 -5
  262. package/src/plugins/builtin/holders/index.tsx +10 -3
  263. package/src/plugins/builtin/holders/pane.tsx +20 -3
  264. package/src/plugins/builtin/holders/report-header.ts +95 -0
  265. package/src/plugins/builtin/holders/table-model.ts +20 -5
  266. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  267. package/src/plugins/builtin/holders/types.ts +2 -1
  268. package/src/plugins/builtin/insider/headless.ts +2 -0
  269. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  270. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  271. package/src/plugins/builtin/jobs/headless.ts +1 -0
  272. package/src/plugins/builtin/jobs/index.tsx +1 -0
  273. package/src/plugins/builtin/jobs/share-bars.tsx +5 -28
  274. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  275. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  276. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  277. package/src/plugins/builtin/market-heatmap/data.ts +30 -2
  278. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  279. package/src/plugins/builtin/market-heatmap/index.tsx +245 -81
  280. package/src/plugins/builtin/market-heatmap/live.ts +88 -0
  281. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  282. package/src/plugins/builtin/market-heatmap/portfolio.ts +50 -11
  283. package/src/plugins/builtin/market-movers/client.ts +3 -2
  284. package/src/plugins/builtin/market-movers/headless.ts +10 -1
  285. package/src/plugins/builtin/market-movers/screener.ts +18 -5
  286. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  287. package/src/plugins/builtin/members/client.ts +53 -0
  288. package/src/plugins/builtin/members/headless.ts +35 -0
  289. package/src/plugins/builtin/members/index.tsx +20 -0
  290. package/src/plugins/builtin/members/model.ts +68 -0
  291. package/src/plugins/builtin/members/pane.tsx +175 -0
  292. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  293. package/src/plugins/builtin/mna/headless.ts +1 -0
  294. package/src/plugins/builtin/mna/index.tsx +2 -1
  295. package/src/plugins/builtin/mna/pane.tsx +5 -2
  296. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  297. package/src/plugins/builtin/news/headless.ts +2 -0
  298. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  299. package/src/plugins/builtin/notes/cli.ts +14 -6
  300. package/src/plugins/builtin/notes/index.tsx +1 -0
  301. package/src/plugins/builtin/openfda/index.tsx +1 -0
  302. package/src/plugins/builtin/options/index.tsx +2 -1
  303. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  304. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  305. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  306. package/src/plugins/builtin/pe-band/client.ts +74 -2
  307. package/src/plugins/builtin/pe-band/headless.ts +26 -8
  308. package/src/plugins/builtin/pe-band/model.ts +102 -22
  309. package/src/plugins/builtin/pe-band/pane.tsx +34 -16
  310. package/src/plugins/builtin/pe-band/report-dates.ts +78 -0
  311. package/src/plugins/builtin/perps/client.ts +66 -5
  312. package/src/plugins/builtin/perps/equity-identity.ts +16 -0
  313. package/src/plugins/builtin/perps/equity-row.tsx +6 -4
  314. package/src/plugins/builtin/perps/headless.ts +144 -16
  315. package/src/plugins/builtin/perps/index.tsx +6 -6
  316. package/src/plugins/builtin/perps/model.ts +189 -12
  317. package/src/plugins/builtin/perps/pane.tsx +248 -47
  318. package/src/plugins/builtin/plugin-marketplace/activation.ts +19 -0
  319. package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -2
  320. package/src/plugins/builtin/plugin-marketplace/store.ts +2 -0
  321. package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
  322. package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
  323. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  324. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  325. package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
  326. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  327. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  328. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  329. package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
  330. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  331. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  332. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  333. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  334. package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
  335. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +43 -2
  336. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +48 -5
  337. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  338. package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
  339. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  340. package/src/plugins/builtin/power/headless.ts +3 -1
  341. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  342. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  343. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  344. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  345. package/src/plugins/builtin/research/events-headless.ts +2 -0
  346. package/src/plugins/builtin/research/headless.ts +2 -0
  347. package/src/plugins/builtin/research/index.tsx +1 -0
  348. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  349. package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
  350. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  351. package/src/plugins/builtin/research-search/index.tsx +1 -0
  352. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  353. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  354. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  355. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  356. package/src/plugins/builtin/scanner/headless.ts +14 -0
  357. package/src/plugins/builtin/scanner/hilo-bars.tsx +12 -70
  358. package/src/plugins/builtin/scanner/hilo-model.ts +0 -18
  359. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  360. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  361. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  362. package/src/plugins/builtin/sec/forms.ts +12 -0
  363. package/src/plugins/builtin/sec/headless.ts +2 -0
  364. package/src/plugins/builtin/sectors/client.ts +1 -0
  365. package/src/plugins/builtin/sectors/headless.ts +9 -1
  366. package/src/plugins/builtin/sectors/move-bar.tsx +10 -32
  367. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  368. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  369. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  370. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  371. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  372. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  373. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  374. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  375. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  376. package/src/plugins/builtin/social-mentions/index.tsx +1 -1
  377. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  378. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  379. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  380. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  381. package/src/plugins/builtin/themes/headless.ts +3 -0
  382. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  383. package/src/plugins/builtin/thirteenf/index.tsx +2 -1
  384. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  385. package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
  386. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  387. package/src/plugins/builtin/ticker-detail/overview/components.tsx +5 -60
  388. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
  389. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +1 -1
  390. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
  391. package/src/plugins/builtin/ticker-detail/pane.tsx +1 -1
  392. package/src/plugins/builtin/ticker-detail/quote-footer.ts +7 -1
  393. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +20 -4
  394. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -2
  395. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  396. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  397. package/src/plugins/builtin/vol-surface/index.tsx +1 -1
  398. package/src/plugins/builtin/volatility/headless.ts +6 -1
  399. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  400. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
  401. package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
  402. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  403. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  404. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  405. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  406. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  407. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  408. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  409. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
  410. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  411. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  412. package/src/plugins/builtin/world-venue-map/index.ts +67 -4
  413. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
  414. package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
  415. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  416. package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
  417. package/src/plugins/builtin/world-venue-map/model.ts +7 -4
  418. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  524. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  525. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  526. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  527. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  528. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  529. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  530. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  531. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  532. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  533. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  534. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  535. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  536. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  537. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  538. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  539. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  540. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  541. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  542. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  543. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  544. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  545. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  546. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  547. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  548. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  549. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  550. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  551. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  552. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  553. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  554. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  555. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  556. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  557. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  558. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  559. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  560. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  561. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  562. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  563. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  564. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  565. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  566. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  567. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  568. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  569. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  570. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  571. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  572. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  573. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  574. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  575. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  576. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  577. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  578. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  579. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  580. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  581. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  582. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  583. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  584. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  585. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  586. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  587. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  588. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  589. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  590. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  591. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  592. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  593. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  594. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  595. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  596. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  597. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  598. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  599. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  600. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  601. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  602. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  603. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  604. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  605. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  606. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  607. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  608. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  609. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  610. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  611. package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
  612. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  613. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  614. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  615. package/src/plugins/catalog-browser.ts +2 -0
  616. package/src/plugins/catalog-manifest.ts +1 -0
  617. package/src/plugins/catalog-ui.ts +3 -1
  618. package/src/plugins/catalog.ts +1 -1
  619. package/src/plugins/host-link.ts +33 -1
  620. package/src/plugins/installer.ts +48 -12
  621. package/src/plugins/loader.ts +30 -3
  622. package/src/plugins/manager-node.ts +15 -5
  623. package/src/plugins/registry/index.ts +1 -1
  624. package/src/plugins/registry/pane-settings.ts +26 -7
  625. package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
  626. package/src/renderers/dom/build-assets.ts +81 -3
  627. package/src/renderers/dom/data-table/row.tsx +52 -16
  628. package/src/renderers/dom/desktop/controls.tsx +7 -3
  629. package/src/renderers/dom/desktop/icons.tsx +1 -0
  630. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  631. package/src/renderers/dom/desktop/popover.tsx +73 -14
  632. package/src/renderers/dom/host/box.tsx +69 -26
  633. package/src/renderers/dom/host/input.tsx +14 -3
  634. package/src/renderers/dom/host/tabs.tsx +37 -1
  635. package/src/renderers/dom/styles.css +41 -7
  636. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +11 -6
  637. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
  638. package/src/renderers/electrobun/bun/desktop/update.ts +181 -87
  639. package/src/renderers/electrobun/bun/index.ts +73 -6
  640. package/src/renderers/electrobun/bun/window/remembered-frame.ts +122 -0
  641. package/src/renderers/electrobun/shared/protocol.ts +3 -0
  642. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  643. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -1
  644. package/src/renderers/electrobun/view/main.tsx +7 -1
  645. package/src/renderers/electrobun/view/renderer-window-error.ts +18 -0
  646. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  647. package/src/renderers/electrobun/view/update-host.ts +45 -21
  648. package/src/renderers/opentui/host.tsx +5 -0
  649. package/src/sources/gloomberb-cloud/index.ts +25 -4
  650. package/src/sources/gloomberb-cloud/normalizers.ts +36 -5
  651. package/src/sources/provider-router/cached-routes.ts +4 -1
  652. package/src/sources/provider-router/financials.ts +11 -8
  653. package/src/sources/provider-router/history.ts +15 -10
  654. package/src/sources/sec-registrant.ts +75 -0
  655. package/src/state/app/context/index.tsx +24 -8
  656. package/src/state/hooks/quote-streaming.ts +41 -26
  657. package/src/sync/core-contributors.ts +4 -0
  658. package/src/telemetry/benign-window-error.ts +7 -0
  659. package/src/telemetry/crash-reports-dom.ts +2 -0
  660. package/src/telemetry/crash-reports.ts +4 -1
  661. package/src/test-support/cli-context.ts +10 -2
  662. package/src/test-support/daily-nav.ts +25 -0
  663. package/src/theme/heat-colors.ts +357 -2
  664. package/src/tickers/instrument-kind.ts +34 -7
  665. package/src/tickers/search/asset-classes.ts +24 -9
  666. package/src/tickers/search/index.ts +44 -11
  667. package/src/tickers/search/ranking.ts +23 -3
  668. package/src/time-series/resolve.ts +1 -1
  669. package/src/time-series/use-chart-resolution.ts +1 -1
  670. package/src/types/context-menu.ts +6 -0
  671. package/src/types/data-provider.ts +2 -0
  672. package/src/types/financials.ts +5 -0
  673. package/src/types/headless.ts +79 -2
  674. package/src/types/plugin.ts +38 -6
  675. package/src/types/ticker.ts +15 -0
  676. package/src/ui/context-menu.tsx +1 -0
  677. package/src/ui/host.tsx +16 -0
  678. package/src/updater/index.ts +38 -13
  679. package/src/utils/async-deadline.ts +21 -0
  680. package/src/utils/cli-output.ts +5 -1
  681. package/src/utils/crypto-pair.ts +41 -0
  682. package/src/utils/currency-units.ts +14 -0
  683. package/src/utils/depositary-receipt.ts +26 -0
  684. package/src/utils/exchanges.ts +72 -0
  685. package/src/utils/fire-and-forget.ts +24 -0
  686. package/src/utils/format.ts +13 -0
  687. package/src/utils/price-earnings.ts +70 -3
  688. package/src/utils/price-history.ts +58 -13
  689. package/src/utils/rpc-timeout-error.ts +27 -0
  690. package/src/utils/sec.ts +13 -1
  691. package/src/utils/utc-time.ts +79 -0
@@ -4,10 +4,14 @@ import {
4
4
  type AccountProfile,
5
5
  type ChatUserSummary,
6
6
  } from "../../../api-client";
7
- import {
8
- PROFILE_POPOVER_CLOSE_DELAY_MS,
9
- hasPublicChatProfileInfo,
10
- } from "./message/profile-popover";
7
+ import { PROFILE_POPOVER_CLOSE_DELAY_MS } from "./message/profile-popover";
8
+ import type { ChatUserAnchor } from "./message/types";
9
+
10
+ interface ProfilePopoverOptions {
11
+ ownProfile?: boolean;
12
+ /** The name or @mention it opens from; the desktop places the card beside it. */
13
+ anchor?: ChatUserAnchor;
14
+ }
11
15
 
12
16
  function accountProfileToChatUser(profile: AccountProfile): ChatUserSummary {
13
17
  return {
@@ -39,6 +43,7 @@ function isAccountProfileConfigured(profile: AccountProfile): boolean {
39
43
 
40
44
  export function useChatProfilePopover(trackOwnProfileUserId?: string) {
41
45
  const [profilePopoverUser, setProfilePopoverUser] = useState<ChatUserSummary | null>(null);
46
+ const [profilePopoverAnchor, setProfilePopoverAnchor] = useState<ChatUserAnchor>(null);
42
47
  const [ownProfileConfigured, setOwnProfileConfigured] = useState<boolean | null>(null);
43
48
  const profilePopoverCloseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
44
49
  const ownProfileRef = useRef<ChatUserSummary | null>(null);
@@ -60,6 +65,7 @@ export function useChatProfilePopover(trackOwnProfileUserId?: string) {
60
65
  pinnedRef.current = false;
61
66
  profilePopoverUserIdRef.current = null;
62
67
  setProfilePopoverUser(null);
68
+ setProfilePopoverAnchor(null);
63
69
  }, [cancelProfilePopoverClose]);
64
70
 
65
71
  const scheduleProfilePopoverClose = useCallback(() => {
@@ -70,6 +76,7 @@ export function useChatProfilePopover(trackOwnProfileUserId?: string) {
70
76
  if (pinnedRef.current) return;
71
77
  profilePopoverUserIdRef.current = null;
72
78
  setProfilePopoverUser(null);
79
+ setProfilePopoverAnchor(null);
73
80
  }, PROFILE_POPOVER_CLOSE_DELAY_MS);
74
81
  }, [cancelProfilePopoverClose]);
75
82
 
@@ -104,32 +111,29 @@ export function useChatProfilePopover(trackOwnProfileUserId?: string) {
104
111
 
105
112
  const showProfilePopover = useCallback((
106
113
  targetUser: ChatUserSummary,
107
- options?: { ownProfile?: boolean; pin?: boolean },
114
+ options?: ProfilePopoverOptions & { pin?: boolean },
108
115
  ) => {
109
116
  const ownProfile = options?.ownProfile === true;
110
117
  const cachedUser = ownProfile && ownProfileRef.current?.id === targetUser.id
111
118
  ? ownProfileRef.current
112
119
  : targetUser;
113
- // Only what the server shared: a private or empty profile has no card.
114
- if (!ownProfile && !hasPublicChatProfileInfo(cachedUser)) {
115
- closeProfilePopover();
116
- return;
117
- }
120
+ // Every name has a card: a private or empty profile gets the name-only one.
118
121
  cancelProfilePopoverClose();
119
122
  pinnedRef.current = options?.pin === true;
120
123
  profilePopoverUserIdRef.current = cachedUser.id;
121
124
  setProfilePopoverUser(cachedUser);
125
+ setProfilePopoverAnchor(options?.anchor ?? null);
122
126
  if (ownProfile) refreshOwnProfile(targetUser.id);
123
- }, [cancelProfilePopoverClose, closeProfilePopover, refreshOwnProfile]);
127
+ }, [cancelProfilePopoverClose, refreshOwnProfile]);
124
128
 
125
129
  /** Pointing at a name previews its card, but never over one a click pinned. */
126
- const hoverProfilePopover = useCallback((targetUser: ChatUserSummary, options?: { ownProfile?: boolean }) => {
130
+ const hoverProfilePopover = useCallback((targetUser: ChatUserSummary, options?: ProfilePopoverOptions) => {
127
131
  if (pinnedRef.current) return;
128
132
  showProfilePopover(targetUser, options);
129
133
  }, [showProfilePopover]);
130
134
 
131
135
  /** A click on a name pins its card until Esc, a click outside, or a second click. */
132
- const toggleProfilePopover = useCallback((targetUser: ChatUserSummary, options?: { ownProfile?: boolean }) => {
136
+ const toggleProfilePopover = useCallback((targetUser: ChatUserSummary, options?: ProfilePopoverOptions) => {
133
137
  // The desktop card hears the same click first, as a click outside it.
134
138
  if (dismissedPinnedUserIdRef.current === targetUser.id) {
135
139
  dismissedPinnedUserIdRef.current = null;
@@ -177,6 +181,7 @@ export function useChatProfilePopover(trackOwnProfileUserId?: string) {
177
181
  closeProfilePopover,
178
182
  dismissProfilePopover,
179
183
  ownProfileConfigured,
184
+ profilePopoverAnchor,
180
185
  profilePopoverUser,
181
186
  hoverProfilePopover,
182
187
  scheduleProfilePopoverClose,
@@ -31,6 +31,7 @@ export const clinicalTrialsPlugin: GloomPlugin = {
31
31
  panes: [
32
32
  {
33
33
  id: CLINICAL_TRIALS_PANE_ID,
34
+ reportFreshness: { source: "ClinicalTrials.gov", status: "not-a-feed", basis: "registry records" },
34
35
  name: "Trials",
35
36
  icon: "C",
36
37
  component: TrialsPane,
@@ -285,7 +285,8 @@ function defaultHeadlessExecutor(
285
285
  return {
286
286
  result: serializeHeadlessPaneResult(loaded.definition, result),
287
287
  rowCount: headlessRowCount(loaded.definition, result),
288
- ...(result.errors?.length ? { errors: result.errors } : {}),
288
+ // Ask Gloom reads a caveat as a partial result, so notes join the errors here.
289
+ ...(result.errors?.length || result.notes?.length ? { errors: [...(result.errors ?? []), ...(result.notes ?? [])] } : {}),
289
290
  };
290
291
  };
291
292
  }
@@ -65,6 +65,7 @@ const askgModule: PluginModule = {
65
65
  },
66
66
  panes: [{
67
67
  id: ASKG_PANE_ID,
68
+ reportFreshness: { status: "not-a-feed", basis: "generated answer" },
68
69
  name: "Ask Gloom",
69
70
  icon: "K",
70
71
  component: ASKGPane,
@@ -23,6 +23,7 @@ export const teamModule: PluginModule = {
23
23
  capabilities: [createCloudTeamCapability(), createCloudViewsCapability()],
24
24
  panes: [{
25
25
  id: TEAM_PANE_ID,
26
+ reportFreshness: { status: "not-a-feed", basis: "account data" },
26
27
  name: "Team",
27
28
  icon: "T",
28
29
  component: TeamPane,
@@ -12,6 +12,7 @@ import { ThesisTickerTab } from "./ticker-tab";
12
12
  export const thesisModule: PluginModule = {
13
13
  panes: [{
14
14
  id: THESIS_PANE_ID,
15
+ reportFreshness: { source: "Your theses", status: "not-a-feed", basis: "your theses" },
15
16
  name: "Theses",
16
17
  icon: "Θ",
17
18
  component: ThesisBoardPane,
@@ -28,6 +28,7 @@ export function registerTwitterFeedFeature(ctx: GloomPluginContext): void {
28
28
 
29
29
  ctx.registerPane({
30
30
  id: TWITTER_FEED_PANE_ID,
31
+ reportFreshness: { source: "X posts", status: "not-a-feed", basis: "posts" },
31
32
  name: "X Feed",
32
33
  icon: "X",
33
34
  component: TwitterFeedPane,
@@ -34,6 +34,7 @@ export const commentLettersPlugin: GloomPlugin = {
34
34
  panes: [
35
35
  {
36
36
  id: COMMENT_LETTERS_PANE_ID,
37
+ reportFreshness: { source: "SEC EDGAR", status: "not-a-feed", basis: "comment letters" },
37
38
  name: "Comment Letters",
38
39
  icon: "L",
39
40
  component: CommentLettersPane,
@@ -7,6 +7,9 @@ import { appsModel, hiringModel, type AttentionKind } from "./model";
7
7
  export function attentionHeadless(kind: AttentionKind): HeadlessPaneDefinition<"bundle"> {
8
8
  return {
9
9
  shape: "bundle",
10
+ freshness: kind === "hiring"
11
+ ? { source: "Company careers sites", status: "not-a-feed", basis: "observed job postings" }
12
+ : { source: "App Store and Google Play charts", status: "not-a-feed", basis: "observed chart ranks" },
10
13
  argument: { kind: "ticker", optional: true, placeholder: "ticker", description: "Company ticker, including exchange for non-US listings. Omit for the global board." },
11
14
  options: [
12
15
  { key: "limit", type: "string", defaultValue: "100", description: "Rows per REST page, up to 200 for hiring and 500 for apps." },
@@ -36,7 +39,8 @@ export function attentionHeadless(kind: AttentionKind): HeadlessPaneDefinition<"
36
39
  const nextOffset = kind === "hiring" && "total" in data ? offset + data.companies.length < data.total ? offset + data.companies.length : null : (data as AppAttentionPayload).page?.nextOffset ?? null;
37
40
  return {
38
41
  complete: !model.preview && nextOffset === null,
39
- errors: [...model.notices, ...(nextOffset !== null ? [`Additional observations available with --offset ${nextOffset}.`] : []), ...(model.preview ? ["Additional rows and history require Gloom Pro."] : [])],
42
+ errors: [...model.notices, ...(model.preview ? ["Additional rows and history require Gloom Pro."] : [])],
43
+ ...(nextOffset !== null ? { notes: [`Additional observations available with --offset ${nextOffset}.`] } : {}),
40
44
  sections: Object.entries(model.sections).map(([key, section]) => ({ title: key === "mix" ? kind === "hiring" ? "Role family" : "Countries" : key,
41
45
  columns: section.columns.map((column) => ({ key: column.id, header: column.label, align: column.align })),
42
46
  rows: section.rows.map((row) => ({ ...row.values, ...(row.url ? { sourceUrl: row.url } : {}), ...(row.details ? { evidence: row.details } : {}) })) })),
@@ -172,7 +172,7 @@ function AttentionView({ kind, symbol, width, height, focused }: Size & { kind:
172
172
  const numeric = typeof value === "number";
173
173
  const decimals = DECIMALS[column.id] ?? 0;
174
174
  const text = numeric ? `${SIGNED_COLUMNS.has(column.id) && value > 0 ? "+" : ""}${value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals })}` : LABEL_COLUMNS.has(column.id) ? humanLabel(value) : column.id === "title" ? value.trim() : value;
175
- if (column.id === "share" && numeric && tab === "mix") return { ...shareCell(text, maxShare ? value / maxShare : null, column.width, colors, state.selected, desktop), value };
175
+ if (column.id === "share" && numeric && tab === "mix") return { ...shareCell(text, maxShare ? value / maxShare : null, column.width, colors, state.selected), value };
176
176
  return { text, value, color: numeric && SIGNED_COLUMNS.has(column.id) ? signedColor(value, colors)
177
177
  : column.id === "name" || column.id === "title" ? colors.textBright : column.id === "date" || column.id === "observed" || column.id === "confidence" ? colors.textDim : colors.text };
178
178
  }} selectedTextOverridesCellColor showHorizontalScrollbar resetScrollKey={`${kind}:${symbol}:${tab}:${mix}:${country}:${chart}`}
@@ -4,6 +4,7 @@ import { companyQuery, fetchCompanyData, type CompanyMode } from "./client";
4
4
  export function companyHeadless(mode: CompanyMode): HeadlessPaneDefinition<"bundle"> {
5
5
  return {
6
6
  shape: "bundle",
7
+ freshness: { source: "Company filings and calls", status: "not-a-feed", basis: "reported data" },
7
8
  argument: { kind: "ticker", description: "Listed company ticker, including exchange-qualified global symbols.", placeholder: "ticker" },
8
9
  discovery: { aliases: [mode === "kpis" ? "KPIS" : "GUIDE"], dataRequirements: ["Gloom Cloud company disclosures"],
9
10
  limitations: ["Pro dataset with a fixed latest preview on Free", "Coverage follows available company disclosures; missing data is not zero", "Compare matching definition, period, currency, basis and scope", "Fiscal labels without explicit calendar dates are retained without inferred dates"] },
@@ -104,6 +104,7 @@ export function createCongressHeadless(
104
104
  ): HeadlessPaneDefinition<"rows"> {
105
105
  return {
106
106
  shape: "rows",
107
+ freshness: { source: "House and Senate disclosures", status: "not-a-feed", basis: "filed reports" },
107
108
  argument: {
108
109
  kind: "ticker",
109
110
  optional: true,
@@ -8,9 +8,19 @@ export interface CorrelationResult {
8
8
 
9
9
  export interface DailyClose {
10
10
  dateKey: string;
11
+ /** A closing price, or a map series' value for the day (a transit count). */
11
12
  close: number;
12
13
  }
13
14
 
15
+ /**
16
+ * How a series moves between two shared dates. Prices use returns. A map
17
+ * series is a daily count that can be zero (Hormuz logs days with no
18
+ * transits), where a return or log change is undefined, so it uses the
19
+ * change in level. Pearson correlation ignores the unit, so the level change
20
+ * needs no scaling.
21
+ */
22
+ export type ChangeBasis = "return" | "difference";
23
+
14
24
  /** Keep the final valid close for each UTC trading date, in chronological order. */
15
25
  export function dailyCloses(points: readonly PricePoint[]): DailyClose[] {
16
26
  const byDate = new Map<string, number>();
@@ -41,11 +51,55 @@ export function alignDailyCloses(left: readonly DailyClose[], right: readonly Da
41
51
  });
42
52
  }
43
53
 
44
- export function correlateDailyCloses(left: readonly DailyClose[], right: readonly DailyClose[], minObservations = 5): CorrelationResult {
45
- const aligned = alignDailyCloses(left, right);
46
- const x = computeReturns(aligned.map((point) => point.leftClose));
47
- const y = computeReturns(aligned.map((point) => point.rightClose));
48
- return { correlation: pearsonCorrelation(x, y, minObservations), sampleSize: x.length };
54
+ /** A map series' daily values, oldest first; zero is a value, unlike a zero close. */
55
+ export function dailyValues(points: readonly { date: Date; value: number | null }[]): DailyClose[] {
56
+ const byDate = new Map<string, number>();
57
+ for (const point of [...points].sort((left, right) => left.date.getTime() - right.date.getTime())) {
58
+ if (point.value === null || !Number.isFinite(point.value) || !Number.isFinite(point.date.getTime())) continue;
59
+ byDate.set(point.date.toISOString().slice(0, 10), point.value);
60
+ }
61
+ return [...byDate].map(([dateKey, close]) => ({ dateKey, close }));
62
+ }
63
+
64
+ export interface PairedChange {
65
+ dateKey: string;
66
+ left: number;
67
+ right: number;
68
+ }
69
+
70
+ function change(previous: number, current: number, basis: ChangeBasis): number {
71
+ return basis === "difference" ? current - previous : previous > 0 ? (current - previous) / previous : Number.NaN;
72
+ }
73
+
74
+ /** Each side's move between consecutive shared dates, dropped for both sides when either is undefined. */
75
+ export function pairedChanges(
76
+ aligned: readonly AlignedDailyClose[],
77
+ leftBasis: ChangeBasis = "return",
78
+ rightBasis: ChangeBasis = "return",
79
+ ): PairedChange[] {
80
+ const changes: PairedChange[] = [];
81
+ for (let index = 1; index < aligned.length; index++) {
82
+ const previous = aligned[index - 1]!;
83
+ const current = aligned[index]!;
84
+ const left = change(previous.leftClose, current.leftClose, leftBasis);
85
+ const right = change(previous.rightClose, current.rightClose, rightBasis);
86
+ if (Number.isFinite(left) && Number.isFinite(right)) changes.push({ dateKey: current.dateKey, left, right });
87
+ }
88
+ return changes;
89
+ }
90
+
91
+ export function correlateDailyCloses(
92
+ left: readonly DailyClose[],
93
+ right: readonly DailyClose[],
94
+ minObservations = 5,
95
+ leftBasis: ChangeBasis = "return",
96
+ rightBasis: ChangeBasis = "return",
97
+ ): CorrelationResult {
98
+ const changes = pairedChanges(alignDailyCloses(left, right), leftBasis, rightBasis);
99
+ return {
100
+ correlation: pearsonCorrelation(changes.map((point) => point.left), changes.map((point) => point.right), minObservations),
101
+ sampleSize: changes.length,
102
+ };
49
103
  }
50
104
 
51
105
  function toDateKey(point: PricePoint): string | null {
@@ -58,17 +112,6 @@ function comparePricePointsByDate(left: PricePoint, right: PricePoint): number {
58
112
  return getPricePointTimestamp(left) - getPricePointTimestamp(right);
59
113
  }
60
114
 
61
- export function computeReturns(closes: number[]): number[] {
62
- const returns: number[] = [];
63
- for (let i = 1; i < closes.length; i++) {
64
- const previous = closes[i - 1]!;
65
- const current = closes[i]!;
66
- if (!Number.isFinite(previous) || !Number.isFinite(current) || previous === 0) continue;
67
- returns.push((current - previous) / previous);
68
- }
69
- return returns;
70
- }
71
-
72
115
  export function pearsonCorrelation(x: number[], y: number[], minObservations = 5): number | null {
73
116
  const n = Math.min(x.length, y.length);
74
117
  if (n < minObservations) return null;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Map series (`GEO:HORMUZ`) in CORR, read through the same parser and
3
+ * resolver G uses, so an alias G charts is one CORR correlates.
4
+ */
5
+ import { loadGeoCatalog, type GeoRequest } from "../../../api-client/geo";
6
+ import type { TimeRange } from "../../../time-series/range";
7
+ import { GEO_SERIES_CAPABILITY_ID, parseSeriesExpression } from "../chart-composer/series-expression";
8
+ import { resolveGeoChartSeries } from "../world-venue-map/geo-series";
9
+ import { dailyValues, type DailyClose } from "./compute";
10
+ import { CORRELATION_HISTORY_RESOLUTION } from "./history";
11
+
12
+ /** The map series a CORR entry names, or null for a ticker. */
13
+ export function geoSeriesToken(entry: string): string | null {
14
+ if (!/^GEO:/i.test(entry.trim())) return null;
15
+ const parsed = parseSeriesExpression(entry);
16
+ return parsed?.kind === "capability" && parsed.capabilityId === GEO_SERIES_CAPABILITY_ID ? parsed.seriesId : null;
17
+ }
18
+
19
+ /** A map series' daily values over the range. A server without map series says so instead of "not found". */
20
+ export async function loadGeoCorrelationHistory(
21
+ request: GeoRequest,
22
+ seriesId: string,
23
+ range: TimeRange,
24
+ signal?: AbortSignal,
25
+ ): Promise<DailyClose[]> {
26
+ try {
27
+ const series = await resolveGeoChartSeries(request, seriesId, { range, resolution: CORRELATION_HISTORY_RESOLUTION }, signal);
28
+ return dailyValues(series.points);
29
+ } catch (error) {
30
+ signal?.throwIfAborted();
31
+ if (!await loadGeoCatalog(request, { signal })) throw new Error("Map series unavailable.");
32
+ throw error;
33
+ }
34
+ }
@@ -25,7 +25,10 @@ export const paneSchemas = {
25
25
  discovery: {
26
26
  id: "return-correlation",
27
27
  aliases: ["correlation", "return correlation", "correlation matrix", "pearson correlation"],
28
- limitations: ["Correlation is computed from daily returns with at least five shared observations."],
28
+ limitations: [
29
+ "Correlation is computed from daily returns with at least five shared observations.",
30
+ "GEO:<series> entries correlate a map series' daily change with the others on shared dates.",
31
+ ],
29
32
  screenshotReadiness: "partial",
30
33
  },
31
34
  },
@@ -1,12 +1,16 @@
1
1
  import type { HeadlessPaneDefinition } from "../../../types/headless";
2
2
  import type { TimeRange } from "../../../time-series/range";
3
- import { formatNumber } from "../../../utils/format";
3
+ import { formatNumber, formatSignificant } from "../../../utils/format";
4
+ import { mixedSessionCloseNote } from "../../../market-data/market/session-close-note";
4
5
  import { resolveHeadlessInstrument, loadHeadlessSymbols } from "../shared/headless-market-data";
5
- import { buildCorrelationMatrix, buildCorrelationSeries, pairKey } from "./matrix/model";
6
+ import { buildCorrelationMatrix, buildCorrelationSeries, buildGeoCorrelationSeries, pairKey, type CorrelationSeries } from "./matrix/model";
7
+ import { geoSeriesToken, loadGeoCorrelationHistory } from "./geo";
6
8
  import { buildRelationshipAnalysis, DEFAULT_RELATIONSHIP_SECOND_SYMBOL } from "./relationship/model";
7
9
  import { paneSchemas } from "./headless-schema";
8
- import { CORRELATION_RETURN_BASIS, loadCorrelationHistory } from "./history";
10
+ import { CORRELATION_RETURN_BASIS, GEO_CORRELATION_CHANGE_BASIS, loadCorrelationHistory } from "./history";
9
11
  import type { HeadlessPaneContext } from "../../../types/headless";
12
+ import { newestReportTime } from "../../../utils/utc-time";
13
+ import { DAILY_CLOSES } from "../shared/report-freshness";
10
14
 
11
15
  async function loadHistory(ctx: HeadlessPaneContext, key: string, range: TimeRange) {
12
16
  const { symbol, exchange } = await resolveHeadlessInstrument(ctx, key);
@@ -14,9 +18,32 @@ async function loadHistory(ctx: HeadlessPaneContext, key: string, range: TimeRan
14
18
  ctx.refresh ? { cacheMode: "refresh" } : undefined);
15
19
  }
16
20
 
21
+ /**
22
+ * Daily closes with the exchange the symbol trades on, which the session note
23
+ * needs. A symbol that is not in the local data names no exchange, so its
24
+ * quote says where it lists; a missing quote only leaves the note out.
25
+ */
26
+ async function loadListedHistory(ctx: HeadlessPaneContext, key: string, range: TimeRange) {
27
+ const { symbol, exchange } = await resolveHeadlessInstrument(ctx, key);
28
+ const [points, quote] = await Promise.all([
29
+ loadHistory(ctx, key, range),
30
+ exchange ? null : (async () => ctx.marketData.getQuote(symbol, "", ctx.refresh ? { cacheMode: "refresh" } : undefined))().catch(() => null),
31
+ ]);
32
+ return { exchange: exchange || quote?.listingExchangeName || quote?.exchangeName || "", points };
33
+ }
34
+
35
+ /** A ticker's daily closes, or a map series' daily values read straight from the Cloud client. */
36
+ async function loadCorrelationInput(ctx: HeadlessPaneContext, key: string, range: TimeRange): Promise<CorrelationSeries> {
37
+ const geo = geoSeriesToken(key);
38
+ if (!geo) return buildCorrelationSeries(key, await loadHistory(ctx, key, range));
39
+ const request = <T,>(path: string, init?: RequestInit) => ctx.apiClient.geo<T>(path, { ...init, signal: init?.signal ?? ctx.signal });
40
+ return buildGeoCorrelationSeries(key, await loadGeoCorrelationHistory(request, geo, range, ctx.signal));
41
+ }
42
+
17
43
  export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
18
44
  ...paneSchemas["correlation-pane"],
19
45
  shape: "rows",
46
+ freshness: DAILY_CLOSES,
20
47
  describe: ({ symbols, options }) => `Correlation Matrix | Daily returns | ${options.rangePreset ?? "1Y"} | ${symbols.join(", ")}`,
21
48
  columns: [
22
49
  { key: "pair", header: "Pair", format: (_value, row) => `${row.left}/${row.right}` },
@@ -25,8 +52,8 @@ export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
25
52
  ],
26
53
  async load({ symbols, options }, ctx) {
27
54
  const range = (options.rangePreset ?? "1Y") as TimeRange;
28
- const loaded = await loadHeadlessSymbols(symbols, ctx, (symbol) => loadHistory(ctx, symbol, range));
29
- const bySymbol = new Map(loaded.entries.map(({ symbol, data }) => [symbol, buildCorrelationSeries(symbol, data)]));
55
+ const loaded = await loadHeadlessSymbols(symbols, ctx, (symbol) => loadCorrelationInput(ctx, symbol, range));
56
+ const bySymbol = new Map(loaded.entries.map(({ symbol, data }) => [symbol, data]));
30
57
  const matrix = buildCorrelationMatrix(symbols, bySymbol);
31
58
  const rows = symbols.flatMap((left, index) => symbols.slice(index + 1).map((right) => {
32
59
  const result = matrix.results.get(pairKey(left, right));
@@ -41,6 +68,7 @@ export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
41
68
  : row.sampleSize < 5 ? "Insufficient shared return observations" : "Zero return variance",
42
69
  }));
43
70
  return {
71
+ freshness: { asOf: newestReportTime(symbols.map((symbol) => bySymbol.get(symbol)?.prices.at(-1)?.dateKey)) },
44
72
  rows, unavailableSymbols,
45
73
  errors: [
46
74
  ...loaded.errors,
@@ -50,6 +78,7 @@ export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
50
78
  range,
51
79
  unavailablePairs,
52
80
  returnAlignment: CORRELATION_RETURN_BASIS,
81
+ ...(symbols.some((symbol) => geoSeriesToken(symbol)) ? { mapSeriesChange: GEO_CORRELATION_CHANGE_BASIS } : {}),
53
82
  availability: symbols.map((symbol) => ({
54
83
  symbol, status: bySymbol.get(symbol)?.status ?? "error", observationCount: bySymbol.get(symbol)?.observationCount ?? 0,
55
84
  ...(bySymbol.get(symbol)?.integrity ? { integrity: bySymbol.get(symbol)!.integrity } : {}),
@@ -64,14 +93,18 @@ export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
64
93
  export const relationshipHeadless: HeadlessPaneDefinition<"series"> = {
65
94
  ...paneSchemas["relationship-graph-pane"],
66
95
  shape: "series",
96
+ freshness: DAILY_CLOSES,
67
97
  describe: ({ symbols, options }) => `Relationship Graph | ${symbols[0]}/${symbols[1] ?? DEFAULT_RELATIONSHIP_SECOND_SYMBOL} | ${options.range ?? "1Y"}`,
68
98
  async load(args, ctx) {
69
99
  const symbols = [args.symbols[0]!, args.symbols[1] ?? DEFAULT_RELATIONSHIP_SECOND_SYMBOL];
70
100
  const range = (args.options.range ?? "1Y") as TimeRange;
71
101
  const correlationWindow = Number(args.options.correlationWindow ?? 120);
72
- const loaded = await loadHeadlessSymbols(symbols, ctx, (symbol) => loadHistory(ctx, symbol, range));
73
- const histories = new Map(loaded.entries.map(({ symbol, data }) => [symbol, data]));
102
+ const loaded = await loadHeadlessSymbols(symbols, ctx, (symbol) => loadListedHistory(ctx, symbol, range));
103
+ const listings = new Map(loaded.entries.map(({ symbol, data }) => [symbol, data]));
104
+ const histories = new Map(loaded.entries.map(({ symbol, data }) => [symbol, data.points]));
74
105
  const analysis = buildRelationshipAnalysis(histories.get(symbols[0]!) ?? [], histories.get(symbols[1]!) ?? [], correlationWindow);
106
+ const [left, right] = symbols.map((symbol) => ({ symbol, ...listings.get(symbol) }));
107
+ const sessionNote = listings.size === 2 ? mixedSessionCloseNote(left!, right!, analysis.aligned.at(-1)?.dateKey) : null;
75
108
  const unavailableSymbols = symbols.filter((symbol) => (histories.get(symbol) ?? []).filter((point) => (
76
109
  Number.isFinite(point.close) && point.close > 0 && Number.isFinite(new Date(point.date).getTime())
77
110
  )).length < 2);
@@ -86,7 +119,7 @@ export const relationshipHeadless: HeadlessPaneDefinition<"series"> = {
86
119
  { id: "correlation", label: `Rolling correlation (${correlationWindow})`, points: analysis.returns.slice(correlationWindow - 1).map(({ date }) => ({ date: date.toISOString(), value: correlations.get(date.getTime()) ?? null })) },
87
120
  ],
88
121
  stats: [
89
- { key: "latestRatio", label: "Latest ratio", value: analysis.latestRatio, formatted: formatNumber(analysis.latestRatio ?? undefined, 4) },
122
+ { key: "latestRatio", label: "Latest ratio", value: analysis.latestRatio, formatted: formatSignificant(analysis.latestRatio ?? undefined) },
90
123
  { key: "latestCorrelation", label: `Rolling correlation (${correlationWindow})`, value: analysis.latestCorrelation, formatted: formatNumber(analysis.latestCorrelation ?? undefined, 3) },
91
124
  ...(["beta", "alpha", "rSquared"] as const).map((key) => ({
92
125
  key, label: { beta: "Beta", alpha: "Alpha", rSquared: "R squared" }[key],
@@ -102,6 +135,7 @@ export const relationshipHeadless: HeadlessPaneDefinition<"series"> = {
102
135
  metadata: {
103
136
  left: symbols[0], right: symbols[1], range, correlationWindow,
104
137
  returnAlignment: CORRELATION_RETURN_BASIS,
138
+ ...(sessionNote ? { notices: [sessionNote] } : {}),
105
139
  firstDate: analysis.aligned.at(0)?.dateKey ?? null,
106
140
  lastDate: analysis.aligned.at(-1)?.dateKey ?? null,
107
141
  ...(analysis.integrity ? { integrity: analysis.integrity } : {}),
@@ -17,3 +17,5 @@ export async function loadCorrelationHistory(
17
17
  }
18
18
 
19
19
  export const CORRELATION_RETURN_BASIS = "Local-price close-to-close returns between shared UTC dates; cash distributions and FX conversion are excluded, and exchange closing times may differ.";
20
+
21
+ export const GEO_CORRELATION_CHANGE_BASIS = "Map series (GEO:) use the change in daily value between the same shared UTC dates, because counts such as transits can be zero.";
@@ -15,7 +15,10 @@ import { useShortcut } from "../../../react/input";
15
15
  import { buildChartKey } from "../../../market-data/selectors";
16
16
  import { formatTickerListInput } from "../../../tickers/list";
17
17
  import { isPlainKey } from "../../../utils/keyboard";
18
- import { formatCorrelation } from "./compute";
18
+ import { useAsyncResource } from "../../../react/async-resource";
19
+ import { cloudGeoRequest } from "../world-venue-map/client";
20
+ import { geoSeriesToken, loadGeoCorrelationHistory } from "./geo";
21
+ import { formatCorrelation, type DailyClose } from "./compute";
19
22
  import {
20
23
  CORRELATION_RANGE_OPTIONS,
21
24
  DEFAULT_CORRELATION_SYMBOLS,
@@ -37,6 +40,7 @@ import {
37
40
  ROW_HEADER_WIDTH,
38
41
  buildCorrelationMatrix,
39
42
  buildCorrelationPaneTitle,
43
+ buildGeoCorrelationSeries,
40
44
  buildStatusSummary,
41
45
  type CorrelationSeries,
42
46
  displaySymbol,
@@ -50,6 +54,13 @@ import { CORRELATION_HISTORY_RESOLUTION } from "./history";
50
54
  import { buildMatrixPairHistory, clampMatrixCursor, matrixChartRows, matrixSelection, moveMatrixCursor, type MatrixCursor } from "./matrix/selection";
51
55
  import { MatrixPairChart } from "./matrix/pair-chart";
52
56
 
57
+ /** A map series' values and when they arrived; after a failed load, the error and any values kept from before. */
58
+ interface GeoSeriesLoad {
59
+ values?: DailyClose[];
60
+ fetchedAt?: number;
61
+ error?: string;
62
+ }
63
+
53
64
  function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
54
65
  const pane = usePaneInstance();
55
66
  const { navigateTicker, pinTicker } = usePluginTickerActions();
@@ -75,9 +86,12 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
75
86
  const matrixScrollRef = useRef<ScrollBoxRenderable | null>(null);
76
87
  const horizontalScrollRef = useRef<ScrollBoxRenderable | null>(null);
77
88
 
89
+ const entries = settings.symbolsError ? [] : settings.symbols;
90
+ const geoEntries = entries.filter((entry) => geoSeriesToken(entry));
91
+ const geoKey = geoEntries.join(",");
78
92
  const instruments = useMemo(() => {
79
93
  if (settings.symbolsError) return [];
80
- return settings.symbols.map((symbol) => {
94
+ return settings.symbols.filter((symbol) => !geoSeriesToken(symbol)).map((symbol) => {
81
95
  const ticker = tickers.get(symbol);
82
96
  return {
83
97
  symbol,
@@ -103,6 +117,28 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
103
117
 
104
118
  const chartEntries = useChartQueries(chartRequests);
105
119
 
120
+ // Map series load beside the tickers; one that fails leaves the others and every ticker pair working.
121
+ // A failed refresh keeps the series' last values for the same range, as a ticker keeps its last history.
122
+ const geoRetainedRef = useRef(new Map<string, { values: DailyClose[]; fetchedAt: number }>());
123
+ const geoLoader = useMemo(() => geoKey ? async () => {
124
+ const range = settings.rangePreset;
125
+ const results = await Promise.allSettled(geoEntries.map((entry) => (
126
+ loadGeoCorrelationHistory(cloudGeoRequest, geoSeriesToken(entry)!, range)
127
+ )));
128
+ return new Map(geoEntries.map((entry, index): [string, GeoSeriesLoad] => {
129
+ const result = results[index]!;
130
+ const key = `${range}|${entry}`;
131
+ if (result.status === "fulfilled") {
132
+ const loaded = { values: result.value, fetchedAt: Date.now() };
133
+ geoRetainedRef.current.set(key, loaded);
134
+ return [entry, loaded];
135
+ }
136
+ const error = result.reason instanceof Error ? result.reason.message : String(result.reason);
137
+ return [entry, { ...geoRetainedRef.current.get(key), error }];
138
+ }));
139
+ } : null, [geoKey, settings.rangePreset]);
140
+ const geoHistory = useAsyncResource(geoLoader, { keepPreviousData: true });
141
+
106
142
  const seriesBySymbol = useMemo(() => {
107
143
  const map = new Map<string, CorrelationSeries>();
108
144
  for (let i = 0; i < instruments.length; i++) {
@@ -112,10 +148,21 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
112
148
  const entry = chartEntries.get(key);
113
149
  map.set(instrument.symbol, getSeriesForEntry(instrument.symbol, entry, settings.rangePreset));
114
150
  }
151
+ for (const symbol of geoEntries) {
152
+ const loaded = geoHistory.data?.get(symbol);
153
+ map.set(symbol, !loaded
154
+ ? { symbol, prices: [], basis: "difference", status: "loading", observationCount: 0 }
155
+ : loaded.values
156
+ ? {
157
+ ...buildGeoCorrelationSeries(symbol, loaded.values),
158
+ loading: geoHistory.loading, refreshError: loaded.error, fetchedAt: loaded.fetchedAt,
159
+ }
160
+ : { symbol, prices: [], basis: "difference", status: "error", observationCount: 0, refreshError: loaded.error });
161
+ }
115
162
  return map;
116
- }, [chartEntries, chartRequests, instruments, settings.rangePreset]);
163
+ }, [chartEntries, chartRequests, instruments, settings.rangePreset, geoKey, geoHistory.data, geoHistory.loading]);
117
164
 
118
- const symbols = instruments.map((instrument) => instrument.symbol);
165
+ const symbols = entries;
119
166
  const symbolsKey = symbols.join(",");
120
167
  const cursor = clampMatrixCursor(cellCursor, symbols.length);
121
168
  const selection = matrixSelection(symbols, cursor);
@@ -139,15 +186,20 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
139
186
  const refresh = useCallback(() => {
140
187
  const coordinator = getSharedMarketDataCoordinator();
141
188
  for (const request of chartRequests) void coordinator?.loadChart(request, { forceRefresh: true });
142
- }, [chartRequests]);
189
+ if (geoKey) void geoHistory.reload();
190
+ }, [chartRequests, geoKey, geoHistory.reload]);
143
191
 
144
192
  const openSymbol = useCallback((symbol: string) => {
193
+ if (geoSeriesToken(symbol)) {
194
+ createPaneFromTemplate("chart-composer-pane", { arg: symbol });
195
+ return;
196
+ }
145
197
  if (tickers.has(symbol)) {
146
198
  pinTicker(symbol, { floating: true, paneType: TICKER_RESEARCH_PANE_ID });
147
199
  return;
148
200
  }
149
201
  navigateTicker(symbol);
150
- }, [navigateTicker, pinTicker, tickers]);
202
+ }, [createPaneFromTemplate, navigateTicker, pinTicker, tickers]);
151
203
 
152
204
  /** Hovered symbols remain a keyboard starting point; Left reaches their row cursor. */
153
205
  const moveCursor = (key: string) => {
@@ -170,6 +222,8 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
170
222
  event.preventDefault();
171
223
  event.stopPropagation();
172
224
  if (hoveredSymbol && symbols.includes(hoveredSymbol)) openSymbol(hoveredSymbol);
225
+ // Ratio and beta are price measures, so a pair with a map series charts both in G instead.
226
+ else if (pair && pair.some((entry) => geoSeriesToken(entry))) createPaneFromTemplate("chart-composer-pane", { arg: formatTickerListInput(pair) });
173
227
  else if (pair) createPaneFromTemplate("relationship-graph-pane", { symbols: pair, arg: formatTickerListInput(pair) });
174
228
  else openSymbol(selection[0]);
175
229
  }
@@ -210,13 +264,13 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
210
264
  }, []);
211
265
 
212
266
  const headerBg = colors.panel;
213
- const rowHeaderWidth = Math.max(
214
- ROW_HEADER_WIDTH,
215
- Math.min(12, Math.max(0, ...symbols.map((symbol) => displaySymbol(symbol).length)) + 2),
216
- );
267
+ const labelWidth = Math.max(0, ...symbols.map((symbol) => displaySymbol(symbol).length));
268
+ const rowHeaderWidth = Math.max(ROW_HEADER_WIDTH, Math.min(12, labelWidth + 2));
269
+ // A map series label (SUEZ.TANKER) is wider than a ticker's: columns keep room for it and the matrix scrolls instead.
270
+ const minCellWidth = Math.max(MIN_MATRIX_CELL_WIDTH, labelWidth + 2);
217
271
  const cellCount = Math.max(1, symbols.length);
218
- const availableCellWidth = Math.floor((Math.max(width - rowHeaderWidth - 4, cellCount * MIN_MATRIX_CELL_WIDTH)) / cellCount);
219
- const cellWidth = Math.max(MIN_MATRIX_CELL_WIDTH, Math.min(MATRIX_CELL_WIDTH, availableCellWidth));
272
+ const availableCellWidth = Math.floor((Math.max(width - rowHeaderWidth - 4, cellCount * minCellWidth)) / cellCount);
273
+ const cellWidth = Math.max(minCellWidth, Math.min(MATRIX_CELL_WIDTH, availableCellWidth));
220
274
  // Rows are exactly as wide as the matrix (after the one-cell inset), so the
221
275
  // zebra and hover bands stop at the last column instead of running on.
222
276
  const matrixRowWidth = 1 + rowHeaderWidth + symbols.length * cellWidth;
@@ -401,9 +455,9 @@ export const correlationModule: PluginModule = {
401
455
  headless: correlationHeadless,
402
456
  paneId: "correlation",
403
457
  label: "Correlation Matrix",
404
- description: "Date-aligned Pearson correlation matrix for ticker returns.",
458
+ description: "Date-aligned Pearson correlation matrix for ticker returns and map series such as GEO:HORMUZ.",
405
459
  keywords: ["correlation", "corr", "matrix", "pearson", "returns", "covariance"],
406
- shortcut: { prefix: "CORR", argPlaceholder: "tickers", argKind: "ticker-list" },
460
+ shortcut: { prefix: "CORR", argPlaceholder: "tickers", argKind: "ticker-list", keepArgToken: (token) => !!geoSeriesToken(token) },
407
461
  wizard: [
408
462
  {
409
463
  key: "tickers",