gloomberb 0.18.2 → 0.18.4

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 (954) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -0,0 +1,264 @@
1
+ import { apiClient } from "../../../api-client";
2
+ import type { HolderData, HolderRecord } from "../../../types/financials";
3
+ import type { TickerHoldings } from "../thirteenf/signals";
4
+ import { logFailure } from "../../../utils/log-failure";
5
+ import { nonUsHolderCaveat } from "./report-header";
6
+
7
+ /**
8
+ * A US listing's 13F holders from the SEC 13F holder index, the list `fn 13F`
9
+ * pages through: every filer that reported the security for the latest
10
+ * quarter, largest first, 25 to a page. HDS shows them in the units of the
11
+ * source's own short list (each position at the latest price, the stake as a
12
+ * share of the class that list divides by), and keeps that short list for a
13
+ * listing abroad and whenever the index cannot be read.
14
+ */
15
+
16
+ /** The most holder rows `fn HDS` and `holders` print. */
17
+ export const HOLDER_ROWS_MAX = 200;
18
+
19
+ /** One filer's position in the security, summed over the ticker's CUSIPs. */
20
+ export interface IndexedHolder {
21
+ cik: string;
22
+ name: string;
23
+ shares: number;
24
+ /** Shares at the prior quarter end: 0 for a new position, undefined when unknown. */
25
+ previousShares?: number;
26
+ }
27
+
28
+ /** The index's holders loaded so far. */
29
+ export interface IndexedHolderList {
30
+ rows: IndexedHolder[];
31
+ /** The report period the positions are as of. */
32
+ period: string;
33
+ /** Every filer that holds the security at the period end. */
34
+ holderCount: number;
35
+ hasMore: boolean;
36
+ nextOffset: number;
37
+ /** A later page failed: the rows are the ones loaded before it, short of the limit asked. */
38
+ partial?: boolean;
39
+ }
40
+
41
+ const usTicker = /^[A-Z0-9]{1,10}(\.[A-Z]{1,2})?$/;
42
+
43
+ /**
44
+ * The ticker to ask the index for, or null when the listing is not a US
45
+ * line: a venue abroad (typed `SAN:EPA` or given apart), another currency,
46
+ * or a home line whose list the service priced from the filings.
47
+ */
48
+ export function indexHolderTicker(
49
+ symbol: string | null | undefined,
50
+ exchange = "",
51
+ data?: Pick<HolderData, "exchange" | "currency" | "valueBasis"> | null,
52
+ ): string | null {
53
+ const [bare = "", typed = ""] = (symbol ?? "").trim().toUpperCase().split(":");
54
+ const ticker = bare.replace(/[/-]/g, ".");
55
+ if (!usTicker.test(ticker)) return null;
56
+ if (nonUsHolderCaveat(typed || exchange, null) != null) return null;
57
+ if (data && (data.valueBasis === "period_end_price" || nonUsHolderCaveat(data.exchange, data.currency ?? "USD") != null)) return null;
58
+ return ticker;
59
+ }
60
+
61
+ /**
62
+ * One page of the index's holders. Rows that exited during the quarter, and
63
+ * option or principal positions, are not holders of the shares; the pages
64
+ * list the period's holders before its exits, so the list ends where the
65
+ * holder count does.
66
+ */
67
+ export function indexedHolderPage(holdings: TickerHoldings): IndexedHolderList {
68
+ const byCik = new Map<string, IndexedHolder & { previousKnown: boolean }>();
69
+ for (const row of holdings.rows) {
70
+ const type = row.type.trim().toUpperCase();
71
+ if (row.action === "exit" || (type && type !== "SH")) continue;
72
+ if (row.shares == null || !(row.shares > 0)) continue;
73
+ const previous = typeof row.previousShares === "number" ? row.previousShares : null;
74
+ const current = byCik.get(row.cik);
75
+ if (!current) {
76
+ byCik.set(row.cik, {
77
+ cik: row.cik,
78
+ name: row.fund,
79
+ shares: row.shares,
80
+ previousShares: previous ?? undefined,
81
+ previousKnown: previous != null,
82
+ });
83
+ continue;
84
+ }
85
+ // Two CUSIPs under one ticker (a re-issued one) are one position.
86
+ current.shares += row.shares;
87
+ current.previousKnown &&= previous != null;
88
+ current.previousShares = current.previousKnown ? (current.previousShares ?? 0) + previous! : undefined;
89
+ }
90
+ return {
91
+ rows: [...byCik.values()].map(({ previousKnown: _known, ...row }) => row),
92
+ period: holdings.period,
93
+ holderCount: holdings.holderCount,
94
+ hasMore: holdings.hasMore && holdings.nextOffset < holdings.holderCount,
95
+ nextOffset: holdings.nextOffset,
96
+ };
97
+ }
98
+
99
+ /** Rows the service gives a page, as `fn 13F` asks for them. */
100
+ const INDEX_PAGE_ROWS = 25;
101
+ /**
102
+ * Pages one list reads at most: twice what the most rows take, for pages
103
+ * whose options and exits leave fewer holders, and never without end.
104
+ */
105
+ const INDEX_PAGES_MAX = Math.ceil(HOLDER_ROWS_MAX / INDEX_PAGE_ROWS) * 2;
106
+
107
+ /** The client the pages come through; headless reports pass their own. */
108
+ export type IndexedHolderClient = Pick<typeof apiClient, "getCloudSec13F">;
109
+
110
+ /** One page of 25, as `fn 13F` asks for it, so the two share the service's copy. */
111
+ export async function loadIndexedHolderPage(
112
+ ticker: string,
113
+ offset: number,
114
+ signal?: AbortSignal,
115
+ client: IndexedHolderClient = apiClient,
116
+ ): Promise<IndexedHolderList> {
117
+ signal?.throwIfAborted();
118
+ const holdings = await client.getCloudSec13F("ticker-holdings", { tickers: ticker, offset, limit: INDEX_PAGE_ROWS }, { signal }) as TickerHoldings;
119
+ signal?.throwIfAborted();
120
+ if (!Array.isArray(holdings?.rows) || typeof holdings.period !== "string") throw new Error(`13F holders of ${ticker} are unreadable`);
121
+ const page = indexedHolderPage(holdings);
122
+ // A page that does not move the offset on ends the list, or it would be asked for again and again.
123
+ return page.nextOffset > offset ? page : { ...page, hasMore: false };
124
+ }
125
+
126
+ /** Later pages after the first; a page of another period starts the list over. */
127
+ function appendIndexedHolders(current: IndexedHolderList, page: IndexedHolderList): IndexedHolderList {
128
+ if (current.period !== page.period) return page;
129
+ const seen = new Set(current.rows.map((row) => row.cik));
130
+ return { ...page, rows: [...current.rows, ...page.rows.filter((row) => !seen.has(row.cik))] };
131
+ }
132
+
133
+ /**
134
+ * The largest `limit` holders, paging as far as that takes, never more than
135
+ * `INDEX_PAGES_MAX` pages. A later page that fails keeps the holders already
136
+ * loaded, marked partial; only a first page that fails leaves the source's list.
137
+ */
138
+ export async function loadIndexedHolders(
139
+ ticker: string,
140
+ limit: number,
141
+ signal?: AbortSignal,
142
+ client: IndexedHolderClient = apiClient,
143
+ ): Promise<IndexedHolderList> {
144
+ let list = await loadIndexedHolderPage(ticker, 0, signal, client);
145
+ for (let pages = 1; list.hasMore && list.rows.length < limit && pages < INDEX_PAGES_MAX; pages += 1) {
146
+ const offset = list.nextOffset;
147
+ let page: IndexedHolderList;
148
+ try {
149
+ page = await loadIndexedHolderPage(ticker, offset, signal, client);
150
+ } catch (error) {
151
+ if (signal?.aborted) throw error;
152
+ logFailure("holders.index", "Read a later page of the 13F holder index failed", null)(error);
153
+ return { ...list, partial: true };
154
+ }
155
+ list = appendIndexedHolders(list, page);
156
+ }
157
+ return list;
158
+ }
159
+
160
+ /** What a list cut short by a failed page says, when it holds fewer rows than were asked for. */
161
+ export function indexedHoldersPartialNote(list: IndexedHolderList | null | undefined, limit: number): string | null {
162
+ if (!list?.partial || list.rows.length >= limit) return null;
163
+ return `13F holders past the largest ${list.rows.length} could not be read this time.`;
164
+ }
165
+
166
+ /** How the source's own rows value and divide a position, which the index's rows take on. */
167
+ export interface IndexedHolderUnits {
168
+ /** The price a position's shares are valued at. */
169
+ price?: number;
170
+ /**
171
+ * The share count a stake is a share of. The source divides by the class
172
+ * the line trades (PBR's receipts stand for the common shares alone), not
173
+ * by every share the company has.
174
+ */
175
+ classShares?: number;
176
+ }
177
+
178
+ function median(values: number[]): number | undefined {
179
+ if (values.length === 0) return undefined;
180
+ const sorted = [...values].sort((left, right) => left - right);
181
+ const middle = Math.floor(sorted.length / 2);
182
+ return sorted.length % 2 ? sorted[middle] : (sorted[middle - 1]! + sorted[middle]!) / 2;
183
+ }
184
+
185
+ /**
186
+ * The units of the source's list: its rows' price (shares times the latest
187
+ * price), else the quote's, and the count its stakes divide by. The stakes
188
+ * are rounded to four places, so the count is taken over all of them, where
189
+ * the largest weigh most.
190
+ */
191
+ export function indexedHolderUnits(data: HolderData | null | undefined, quotePrice?: number | null): IndexedHolderUnits {
192
+ const rows = (data?.holders ?? []).filter((row) => row.ownerType === "institution" && row.shares != null && row.shares > 0);
193
+ const price = median(rows.flatMap((row) => (row.value != null && row.value > 0 ? [row.value / row.shares!] : [])))
194
+ ?? (quotePrice != null && Number.isFinite(quotePrice) && quotePrice > 0 ? quotePrice : undefined);
195
+ const staked = rows.filter((row) => row.percentHeld != null && row.percentHeld > 0);
196
+ const held = staked.reduce((sum, row) => sum + row.percentHeld!, 0);
197
+ const classShares = held > 0 ? staked.reduce((sum, row) => sum + row.shares!, 0) / held : undefined;
198
+ return {
199
+ ...(price != null ? { price } : {}),
200
+ ...(classShares != null && Number.isFinite(classShares) ? { classShares } : {}),
201
+ };
202
+ }
203
+
204
+ /** The source's rows of the period by their shares, where only one row has that many. */
205
+ function sourceRowsByShares(source: readonly HolderRecord[], period: string): Map<number, HolderRecord> {
206
+ const counts = new Map<number, number>();
207
+ for (const row of source) if (row.reportDate === period && row.shares != null) counts.set(row.shares, (counts.get(row.shares) ?? 0) + 1);
208
+ return new Map(source.flatMap((row) => row.reportDate === period && row.shares != null && counts.get(row.shares) === 1 ? [[row.shares, row]] : []));
209
+ }
210
+
211
+ /**
212
+ * The index's filers as holder rows. A filer whose position is exactly one of
213
+ * the source's rows keeps that row's value and stake, so the largest holders
214
+ * read as they did; the others are valued and divided in the same units.
215
+ */
216
+ function indexedHolderRecords(
217
+ rows: readonly IndexedHolder[],
218
+ period: string,
219
+ units: IndexedHolderUnits,
220
+ source: readonly HolderRecord[] = [],
221
+ ): HolderRecord[] {
222
+ const known = sourceRowsByShares(source, period);
223
+ return rows.map((row) => {
224
+ const change = row.previousShares == null ? undefined : row.shares - row.previousShares;
225
+ const same = known.get(row.shares);
226
+ const value = same?.value ?? (units.price != null ? Math.round(row.shares * units.price) : undefined);
227
+ const percentHeld = same?.percentHeld ?? (units.classShares != null ? row.shares / units.classShares : undefined);
228
+ return {
229
+ ownerType: "institution",
230
+ // The source's spelling of the same holder, not the filer's capitals.
231
+ name: same?.name ?? row.name,
232
+ cik: row.cik,
233
+ reportDate: period,
234
+ shares: row.shares,
235
+ ...(value != null ? { value } : {}),
236
+ ...(percentHeld != null ? { percentHeld } : {}),
237
+ ...(change != null ? { changeShares: change } : {}),
238
+ // A fraction of the prior position, as every holder record carries it; a new one has none.
239
+ ...(change != null && row.previousShares! > 0
240
+ ? { changePercent: Math.round((change / row.previousShares!) * 1e6) / 1e6 }
241
+ : {}),
242
+ };
243
+ });
244
+ }
245
+
246
+ /**
247
+ * The holder list with the index's filers in place of the source's few: the
248
+ * listing's facts and units as the source gave them, the index's period and
249
+ * count.
250
+ */
251
+ export function withIndexedHolders(
252
+ data: HolderData | null | undefined,
253
+ symbol: string,
254
+ list: IndexedHolderList,
255
+ units: IndexedHolderUnits,
256
+ ): HolderData {
257
+ return {
258
+ ...(data ?? { symbol, currency: "USD" }),
259
+ asOf: list.period,
260
+ holders: indexedHolderRecords(list.rows, list.period, units, data?.holders),
261
+ summary: { ...data?.summary, institutionsCount: list.holderCount },
262
+ ...(units.price != null ? { valueBasis: "latest_price" as const } : {}),
263
+ };
264
+ }
@@ -1,13 +1,16 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
- import { Box, Text, TextAttributes, useUiCapabilities } from "../../../ui";
2
+ import { Box, Text, TextAttributes, useUiCapabilities, type ScrollBoxRenderable } from "../../../ui";
3
3
  import {
4
4
  Badge,
5
5
  DataTableView,
6
+ usePagedRows,
6
7
  usePaneFooter,
7
8
  usePaneTabs,
8
9
  usePaneTicker,
10
+ useTableLoadMore,
9
11
  type DataTableCell,
10
12
  type DataTableKeyEvent,
13
+ type PageRequest,
11
14
  } from "../../../components";
12
15
  import { handleRefreshKey, loadingErrorFooterInfo } from "../../../components/data-table/table-pane";
13
16
  import { useAsyncResource } from "../../../react/async-resource";
@@ -22,8 +25,8 @@ import { THIRTEENF_TEMPLATE_ID } from "../thirteenf/model";
22
25
  import { useInResearchTab } from "../ticker-detail/research-tab-keys";
23
26
  import {
24
27
  displayDate,
28
+ formatHolderChangePercent,
25
29
  formatHolderOwnershipPercent,
26
- formatMaybePercent,
27
30
  formatMoneyCompact,
28
31
  formatSignedCompact,
29
32
  holderStakeMarketCap,
@@ -40,15 +43,23 @@ import {
40
43
  sortRows,
41
44
  VIEW_TABS,
42
45
  } from "./table-model";
43
- import { classSharesToday, loadHolderData } from "./client";
46
+ import { classSharesAsOf, classSharesToday, loadHolderData } from "./client";
44
47
  import { HoldersTreemap } from "./treemap";
45
48
  import { BeneficialOwnersView } from "./beneficial-view";
46
49
  import { useIssuerListing } from "../shared/ticker-request";
47
50
  import type { HolderColumn, HolderColumnId, HolderRow, SortPreference, ViewMode } from "./types";
48
51
  import { loadHolder13FMatches, type Holder13FMatch } from "./thirteenf-match";
52
+ import { indexedHolderUnits, indexHolderTicker, loadIndexedHolderPage, withIndexedHolders } from "./index-holders";
49
53
  import { useSampledValue, useTickerQuoteStream } from "../../../state/hooks/live-ticker-financials";
50
54
 
51
55
  const HOLDER_MARKET_CAP_SAMPLE_MS = 5_000;
56
+ /** Rows past the end of the table that a scroll loads the next page within, as `useTableLoadMore` does. */
57
+ const LOAD_MORE_ROWS = 8;
58
+
59
+ /** Index rows have their CIK, so their 13F filing needs no name search. */
60
+ function cikMatches(rows: readonly HolderRow[]): Map<string, Holder13FMatch> {
61
+ return new Map(rows.flatMap((row) => row.cik ? [[row.id, { cik: row.cik, fundName: row.name, periodOfReport: row.reportDate }]] : []));
62
+ }
52
63
 
53
64
  /** The width of a three-letter badge ("13F", "ADR"): the label and its padding. */
54
65
  const BADGE_WIDTH = 5;
@@ -64,6 +75,7 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
64
75
  const [fundMatching, setFundMatching] = useState(false);
65
76
  const [selectedId, setSelectedId] = useState<string | null>(null);
66
77
  const fundMatchAbortRef = useRef<AbortController | null>(null);
78
+ const tableScrollRef = useRef<ScrollBoxRenderable | null>(null);
67
79
 
68
80
  const exchange = ticker?.metadata.exchange ?? "";
69
81
  const issuerListing = useIssuerListing(ticker);
@@ -80,8 +92,33 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
80
92
  keepPreviousData: true,
81
93
  });
82
94
 
95
+ // A US line's 13F holders are every filer in the SEC holder index, paged
96
+ // as fn 13F pages them and asked beside the source's short list, which
97
+ // stands until the first page answers and whenever the index cannot be read.
98
+ const indexTicker = indexHolderTicker(symbol, exchange);
99
+ const loadIndexPage = useMemo(() => indexTicker
100
+ ? ({ offset, signal }: PageRequest) => loadIndexedHolderPage(indexTicker, offset, signal)
101
+ : null, [indexTicker]);
102
+ const index = usePagedRows(loadIndexPage, { getId: (row) => row.cik });
103
+ // The source's list kept from the previous ticker must not price this one's filers: they wait for its own.
104
+ const base = data && indexHolderTicker(data.symbol) === indexTicker ? data : null;
105
+ const indexed = index.rows.length > 0 && (!!base || !loading) && indexHolderTicker(symbol, exchange, base) != null;
106
+ const indexPending = !!indexTicker && index.loading && index.rows.length === 0;
107
+ // Index rows take the source's price; the quote's only when the source gave none, sampled so ticks do not re-sort.
108
+ // The rows follow the units in use, so a quote that is not the price used leaves them as they are.
109
+ const quotePrice = useSampledValue(financials?.quote?.price, HOLDER_MARKET_CAP_SAMPLE_MS, symbol ?? "");
110
+ const { price: unitPrice, classShares: unitClassShares } = indexedHolderUnits(base, quotePrice);
111
+ const listData = useMemo(() => {
112
+ const first = index.pages[0];
113
+ if (!indexed || !first || !indexTicker) return data;
114
+ return withIndexedHolders(base, indexTicker, { ...first, rows: index.rows }, {
115
+ ...(unitPrice != null ? { price: unitPrice } : {}),
116
+ ...(unitClassShares != null ? { classShares: unitClassShares } : {}),
117
+ });
118
+ }, [base, data, index.pages, index.rows, indexTicker, indexed, unitClassShares, unitPrice]);
119
+
83
120
  // The values' own currency: dollars from the 13F filings on a London line, not its pence.
84
- const currency = holderValueCurrency(data, ticker?.metadata.currency || "USD")!;
121
+ const currency = holderValueCurrency(listData, ticker?.metadata.currency || "USD")!;
85
122
  // A stake without a reported percentage is the holding's value over the
86
123
  // market cap, when both are in one currency. The stream keeps the cap
87
124
  // current, about once a second; the stakes follow it at most every few
@@ -91,10 +128,11 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
91
128
  const marketCap = useSampledValue(liveMarketCap, HOLDER_MARKET_CAP_SAMPLE_MS, `${symbol ?? ""}:${currency}`);
92
129
  // Today's share count, which a 13D/13G report's own base is checked against.
93
130
  const sharesOutstanding = classSharesToday(financials);
94
- const rows = useMemo(() => buildRows(data), [data]);
131
+ const sharesOutstandingAsOf = classSharesAsOf(financials);
132
+ const rows = useMemo(() => buildRows(listData), [listData]);
95
133
  const periodsDiffer = useMemo(() => holderPeriodsDiffer(rows), [rows]);
96
134
  const sortedRows = useMemo(() => sortRows(rows, sortPreference, marketCap), [marketCap, rows, sortPreference]);
97
- // Change columns only when the source reports a change; otherwise they read "-" on every row.
135
+ // Change columns only when the source reports a change; otherwise every row would read as missing.
98
136
  const showChange = useMemo(() => hasHolderChanges(rows), [rows]);
99
137
  const columns = useMemo(() => buildColumns(width, showChange), [showChange, width]);
100
138
  const selectedIdx = selectedId
@@ -114,8 +152,14 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
114
152
  // restart 25 two-request 13F lookups.
115
153
  useEffect(() => {
116
154
  fundMatchAbortRef.current?.abort();
155
+ if (rows.length > 0 && rows.every((row) => row.cik)) {
156
+ setFundMatches(cikMatches(rows));
157
+ setFundMatching(false);
158
+ return;
159
+ }
117
160
  setFundMatches(new Map());
118
- if (rows.length === 0) {
161
+ // The source's rows are not matched while the index's may replace them.
162
+ if (rows.length === 0 || indexPending) {
119
163
  setFundMatching(false);
120
164
  return;
121
165
  }
@@ -138,7 +182,7 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
138
182
  fundMatchAbortRef.current = null;
139
183
  }
140
184
  };
141
- }, [rows]);
185
+ }, [indexPending, rows]);
142
186
 
143
187
  const selectedRow = activeIdx >= 0 ? sortedRows[activeIdx] ?? null : null;
144
188
  const selectedFundMatch = selectedRow ? fundMatches.get(selectedRow.id) ?? null : null;
@@ -167,9 +211,12 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
167
211
  setViewMode(nextViewMode);
168
212
  }, [setViewMode]);
169
213
 
214
+ const reloadIndex = index.reload;
170
215
  const refresh = useCallback(() => {
171
216
  void reload();
172
- }, [reload]);
217
+ reloadIndex();
218
+ }, [reload, reloadIndex]);
219
+ const loadMoreFromScroll = useTableLoadMore(tableScrollRef, indexed && index.hasMore, index.loadMore);
173
220
 
174
221
  // Plain keys only: Cmd/Ctrl+Shift+R, S and O resize, share and pop out the pane.
175
222
  const handleKeyDown = useCallback((event: DataTableKeyEvent) => {
@@ -261,7 +308,7 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
261
308
  };
262
309
  case "changePercent":
263
310
  return {
264
- text: formatMaybePercent(row.changePercent),
311
+ text: formatHolderChangePercent(row.changePercent),
265
312
  color: row.changePercent != null ? priceColor(row.changePercent) : colors.textDim,
266
313
  };
267
314
  case "percentHeld":
@@ -282,8 +329,14 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
282
329
  // One date only when every holder's row is of it; the PERIOD column dates each row.
283
330
  ...(periodsDiffer
284
331
  ? [{ id: "as-of", parts: [{ text: "latest period per holder", tone: "muted" as const }] }]
285
- : data?.asOf ? [{ id: "as-of", parts: [{ text: data.asOf, tone: "value" as const }] }] : []),
286
- ...loadingErrorFooterInfo(loading, data ? error : null),
332
+ : listData?.asOf ? [{ id: "as-of", parts: [{ text: listData.asOf, tone: "value" as const }] }] : []),
333
+ // The index's first page replaces the source's list, so it is loading too; a failed one leaves that list.
334
+ ...loadingErrorFooterInfo(loading || (indexPending && !!data), listData ? error : null),
335
+ ...(index.loadingMore ? [{ id: "loading-more", parts: [{ text: "loading more", tone: "muted" as const }] }] : []),
336
+ // A later page that failed keeps the rows loaded; scrolling asks for it again.
337
+ ...(indexed && index.moreError && !index.loadingMore
338
+ ? [{ id: "more-error", parts: [{ text: "more holders could not be read", tone: "warning" as const }] }]
339
+ : []),
287
340
  ...(fundMatching ? [{ id: "fund-matching", parts: [{ text: "13F matching", tone: "muted" as const }] }] : []),
288
341
  ],
289
342
  // The title-bar tabs (or the query bar inside Ticker Research) switch
@@ -293,7 +346,7 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
293
346
  ...(selectedFundMatch ? [{ id: "fund", key: "o", label: "pen 13F", onPress: () => openFundDetail(selectedRow) }] : []),
294
347
  ],
295
348
  };
296
- }, [data, error, fundMatching, loading, openFundDetail, periodsDiffer, selectedFundMatch, selectedRow, viewMode]);
349
+ }, [data, error, fundMatching, index.loadingMore, index.moreError, indexed, indexPending, listData, loading, openFundDetail, periodsDiffer, selectedFundMatch, selectedRow, viewMode]);
297
350
 
298
351
  const selectView = useCallback((value: string) => setViewMode(value as ViewMode), [setViewMode]);
299
352
  // As a research tab, h/l move between research tabs; `s` switches the view.
@@ -313,11 +366,19 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
313
366
  // values" while the request is still in flight or the pane has no ticker.
314
367
  const statusTitle = !symbol
315
368
  ? "No ticker selected."
316
- : loading && !data
369
+ : (loading || indexPending) && !listData
317
370
  ? "Loading holders..."
318
- : !data && error ? error : sortedRows.length === 0 ? "No holders available" : null;
371
+ : !listData && error ? error : sortedRows.length === 0 ? "No holders available" : null;
319
372
  const chartHeight = Math.max(1, height - tabRows - (nativePaneChrome ? 1 : 0));
320
373
 
374
+ // A list shorter than the table cannot scroll to load more, so it pages on
375
+ // until it fills the table, as a scroll would; a failed page waits for one.
376
+ const { hasMore: indexHasMore, loading: indexLoading, loadingMore: indexLoadingMore, moreError: indexMoreError, loadMore: loadMoreIndex } = index;
377
+ useEffect(() => {
378
+ if (viewMode !== "table" || !indexed || !indexHasMore || indexLoading || indexLoadingMore || indexMoreError) return;
379
+ if (sortedRows.length < chartHeight + LOAD_MORE_ROWS) loadMoreIndex();
380
+ }, [chartHeight, indexHasMore, indexLoading, indexLoadingMore, indexMoreError, indexed, loadMoreIndex, sortedRows.length, viewMode]);
381
+
321
382
  return (
322
383
  <Box flexDirection="column" width={width} height={height}>
323
384
  {nativePaneChrome ? tabStrip : tabStrip && <Box height={1} paddingX={1}>{tabStrip}</Box>}
@@ -333,6 +394,8 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
333
394
  }}
334
395
  onActivate={openFundDetail}
335
396
  onRootKeyDown={handleKeyDown}
397
+ scrollRef={tableScrollRef}
398
+ onBodyScrollActivity={loadMoreFromScroll}
336
399
  resetScrollKey={data?.symbol}
337
400
  rootWidth={width}
338
401
  columns={columns}
@@ -354,6 +417,7 @@ export function HoldersView({ focused, width, height }: { focused: boolean; widt
354
417
  holderRows={rows}
355
418
  fundMatches={fundMatches}
356
419
  sharesOutstanding={sharesOutstanding}
420
+ sharesOutstandingAsOf={sharesOutstandingAsOf}
357
421
  onCycleView={toggleView}
358
422
  onRefreshHolders={refresh}
359
423
  />
@@ -1,8 +1,9 @@
1
1
  import type { HeadlessPaneColumn } from "../../../types/plugin";
2
2
  import type { HolderData, ShareBasis } from "../../../types/financials";
3
- import { formatCompact, formatPercentRaw } from "../../../utils/format";
3
+ import { formatCompact, MISSING_VALUE } from "../../../utils/format";
4
4
  import {
5
5
  displayDate,
6
+ formatChangePercent,
6
7
  formatMoneyCompact,
7
8
  formatPercentHeld,
8
9
  formatSignedCompact,
@@ -21,6 +22,7 @@ import {
21
22
  nonUsHolderCaveat,
22
23
  sharedReportDate,
23
24
  } from "./report-header";
25
+ import { HOLDER_ROWS_MAX } from "./index-holders";
24
26
  import { buildRows, DEFAULT_SORT, sortRows } from "./table-model";
25
27
  import type { HolderColumnId, SortPreference } from "./types";
26
28
 
@@ -28,7 +30,8 @@ import type { HolderColumnId, SortPreference } from "./types";
28
30
  * A holder as `holders` and `fn HDS` report it; the keys are the JSON
29
31
  * contract. `value` is in `currency`, the values' own currency; the percents
30
32
  * are in percent (0.59 is 0.59% of the shares outstanding, 13.15 a 13.15%
31
- * change on the quarter). A figure the source did not give is null.
33
+ * change on the quarter, 108.6 a position that more than doubled), from the
34
+ * record's fractions. A figure the source did not give is null.
32
35
  */
33
36
  export interface HolderReportRow {
34
37
  name: string;
@@ -63,14 +66,14 @@ export const HOLDER_REPORT_COLUMNS: HeadlessPaneColumn[] = [
63
66
  key: "value",
64
67
  header: "Mkt value",
65
68
  align: "right",
66
- format: (value) => num(value) == null ? "-" : formatCompact(num(value)!),
69
+ format: (value) => num(value) == null ? MISSING_VALUE : formatCompact(num(value)!),
67
70
  textFormat: (value, row) => formatMoneyCompact(num(value) ?? undefined, String(row.currency ?? "USD")),
68
71
  },
69
72
  {
70
73
  key: "shares",
71
74
  header: "Amount",
72
75
  align: "right",
73
- format: (value) => num(value) == null ? "-" : formatCompact(num(value)!),
76
+ format: (value) => num(value) == null ? MISSING_VALUE : formatCompact(num(value)!),
74
77
  },
75
78
  {
76
79
  key: BASIS_COLUMN_KEY,
@@ -87,13 +90,13 @@ export const HOLDER_REPORT_COLUMNS: HeadlessPaneColumn[] = [
87
90
  key: "changePercent",
88
91
  header: "Chg%",
89
92
  align: "right",
90
- format: (value) => num(value) == null ? "-" : formatPercentRaw(num(value)!),
93
+ format: (value) => formatChangePercent(num(value)),
91
94
  },
92
95
  {
93
96
  key: "percentHeld",
94
97
  header: "Held",
95
98
  align: "right",
96
- format: (value) => num(value) == null ? "-" : `${num(value)!.toFixed(2)}%`,
99
+ format: (value) => num(value) == null ? MISSING_VALUE : `${num(value)!.toFixed(2)}%`,
97
100
  textFormat: (value) => formatPercentHeld(num(value)),
98
101
  },
99
102
  {
@@ -186,10 +189,13 @@ export function holderReportNotices({
186
189
  reported,
187
190
  total,
188
191
  sort = DEFAULT_SORT,
192
+ indexed = false,
189
193
  }: {
190
194
  data: HolderData;
191
195
  /** The symbol as asked for, which `fn 13F` takes. */
192
196
  requested: string;
197
+ /** The rows are the SEC 13F holder index's, largest first, not the source's short list. */
198
+ indexed?: boolean;
193
199
  shown: readonly HolderReportRow[];
194
200
  /** Holders on the list before a limit. */
195
201
  reported: number;
@@ -218,8 +224,14 @@ export function holderReportNotices({
218
224
  `Mkt value = ${valueBasis}.`,
219
225
  changeReported ? "" : `Change vs prior quarter: not reported by this source; see fn 13F ${requested}`,
220
226
  ].filter(Boolean).join(" ");
227
+ const cut = indexed
228
+ ? indexedListCut(requested, shown.length, total, sort)
229
+ // The source names only its largest holders, so a higher limit shows no more of them.
230
+ : shown.length > 0 && shown.length === reported && total != null && total > reported
231
+ ? `The source lists its ${reported} largest holders; fn 13F ${requested} lists all ${total.toLocaleString("en-US")}.`
232
+ : null;
221
233
  return {
222
- notices: [header, basis, positionsBasis, holderShareBasisNote(data, shown), unvaluedHoldersNote(shown, sort)]
234
+ notices: [header, basis, cut, positionsBasis, holderShareBasisNote(data, shown), unvaluedHoldersNote(shown, sort)]
223
235
  .filter((line): line is string => !!line),
224
236
  valueBasis,
225
237
  positionsBasis,
@@ -227,6 +239,22 @@ export function holderReportNotices({
227
239
  };
228
240
  }
229
241
 
242
+ /**
243
+ * What a cut index list leaves out: the rows are its largest holders, so
244
+ * another order ranks only those, and `--limit` or `fn 13F` shows the rest.
245
+ */
246
+ function indexedListCut(requested: string, shown: number, total: number | null, sort: SortPreference): string | null {
247
+ if (shown === 0 || total == null || shown >= total) return null;
248
+ const within = sort.columnId === "value" || sort.columnId === "shares" ? "" : `Sorted among the ${shown} largest. `;
249
+ const all = total.toLocaleString("en-US");
250
+ const more = total <= HOLDER_ROWS_MAX
251
+ ? `--limit ${total} lists them all.`
252
+ : shown < HOLDER_ROWS_MAX
253
+ ? `--limit lists up to ${HOLDER_ROWS_MAX}; fn 13F ${requested} lists all ${all}.`
254
+ : `fn 13F ${requested} lists all ${all}.`;
255
+ return within + more;
256
+ }
257
+
230
258
  /**
231
259
  * Holders the list gives no value for (a home line's position its filing
232
260
  * could not tie to a priced security) sort after every valued one, and a
@@ -23,7 +23,8 @@ export function nextViewMode(current: ViewMode): ViewMode {
23
23
  export function buildRows(data: HolderData | null): HolderRow[] {
24
24
  return (data?.holders ?? []).map((holder, index) => ({
25
25
  ...holder,
26
- id: `${holder.ownerType}:${holder.name}:${holder.reportDate ?? ""}:${index}`,
26
+ // A filer's CIK names its row across pages; the source's rows have none.
27
+ id: holder.cik ? `cik:${holder.cik}` : `${holder.ownerType}:${holder.name}:${holder.reportDate ?? ""}:${index}`,
27
28
  }));
28
29
  }
29
30
 
@@ -2,6 +2,7 @@ import { listThirteenFForms, normalizeCik, searchThirteenFFunds } from "../thirt
2
2
  import { isoDateToday, isoDateYearsAgo } from "../../../utils/calendar-date";
3
3
  import { buildPeriodReports } from "../thirteenf/model";
4
4
  import type { HolderRow } from "./types";
5
+ import { logFailure } from "../../../utils/log-failure";
5
6
 
6
7
  export interface Holder13FMatch {
7
8
  cik: string;
@@ -100,8 +101,9 @@ export async function loadHolder13FMatches(
100
101
  filedAsOfDate: form?.filedAsOfDate,
101
102
  tableValueTotal: report?.complete && forms.length < 100 ? report.tableValueTotal : null,
102
103
  });
103
- } catch {
104
+ } catch (error) {
104
105
  // Matching 13F metadata is an enhancement; holder rows should remain usable.
106
+ if (!signal.aborted) logFailure("holders.thirteenf-match", "Match holder fund filings failed")(error);
105
107
  }
106
108
  }
107
109
  }
@@ -2,8 +2,8 @@ import { useMemo } from "react";
2
2
  import { MetricTreemapSurface, type MetricTreemapItem } from "../../../components/metric-treemap";
3
3
  import { formatCompact } from "../../../utils/format";
4
4
  import {
5
+ formatHolderChangePercent,
5
6
  formatHolderOwnershipLine,
6
- formatMaybePercent,
7
7
  formatMoneyCompact,
8
8
  } from "./format";
9
9
  import type { HolderRow } from "./types";
@@ -22,7 +22,7 @@ export function HoldersTreemap({ rows, width, height, selectedId, onSelect, onAc
22
22
  }) {
23
23
  const items = useMemo<Array<MetricTreemapItem<HolderRow>>>(() => rows.map((row) => {
24
24
  const ownership = formatHolderOwnershipLine(row, marketCap);
25
- const change = row.changePercent != null ? formatMaybePercent(row.changePercent) : "No change";
25
+ const change = row.changePercent != null ? formatHolderChangePercent(row.changePercent) : "No change";
26
26
  return {
27
27
  id: row.id,
28
28
  label: row.name,