gloomberb 0.16.1 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +26 -8
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +2 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +37 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +2 -0
- package/src/brokers/account-cache.ts +24 -0
- package/src/cli/commands/command-utils.ts +8 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +414 -106
- package/src/cli/commands/overview.ts +77 -32
- package/src/cli/commands/ticker.ts +101 -43
- package/src/cli/desktop-pane-shot.ts +34 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +1 -0
- package/src/cli/helpers.ts +4 -8
- package/src/cli/index.ts +12 -2
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +20 -2
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +27 -20
- package/src/cli/pane-functions/headless.ts +39 -11
- package/src/cli/pane-functions/index.ts +15 -4
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +35 -7
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +7 -3
- package/src/cli/result.ts +41 -27
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/view.tsx +29 -10
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +11 -11
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +14 -3
- package/src/components/metric-treemap/heat-surface.tsx +43 -16
- package/src/components/metric-treemap/heat-tiles.ts +18 -0
- package/src/components/metric-treemap/layout.ts +2 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/range-track.tsx +10 -3
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +7 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/data/config/store/normalize.ts +17 -1
- package/src/i18n/es.ts +19 -1
- package/src/i18n/ja.ts +19 -1
- package/src/i18n/ko.ts +19 -1
- package/src/i18n/zh-cn.ts +19 -1
- package/src/i18n/zh-tw.ts +19 -1
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +78 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +2 -0
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/risk-client.ts +191 -66
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
- package/src/plugins/builtin/analytics/risk-model.ts +45 -17
- package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
- package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/headless.ts +139 -5
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +20 -3
- package/src/plugins/builtin/holders/report-header.ts +95 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +2 -0
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
- package/src/plugins/builtin/market-movers/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +20 -3
- package/src/plugins/builtin/members/headless.ts +5 -3
- package/src/plugins/builtin/members/model.ts +10 -2
- package/src/plugins/builtin/members/pane.tsx +13 -6
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +48 -3
- package/src/plugins/builtin/pe-band/headless.ts +25 -7
- package/src/plugins/builtin/pe-band/model.ts +92 -16
- package/src/plugins/builtin/pe-band/pane.tsx +33 -16
- package/src/plugins/builtin/perps/client.ts +50 -3
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +248 -47
- package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +67 -4
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
- package/src/plugins/builtin/world-venue-map/model.ts +7 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/loader.ts +13 -1
- package/src/plugins/registry/pane-settings.ts +1 -0
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/styles.css +6 -7
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +27 -3
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financials.ts +8 -7
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/theme/heat-colors.ts +266 -84
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +3 -0
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +20 -1
- package/src/types/ticker.ts +15 -0
- package/src/ui/host.tsx +14 -0
- package/src/updater/index.ts +9 -11
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +14 -0
- package/src/utils/depositary-receipt.ts +26 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { currencyUnitLabel, resolveCurrencyUnit } from "../../../utils/currency-units";
|
|
2
|
+
import { canonicalExchange, isUsListingExchange, resolveExchangeTimeZone } from "../../../utils/exchanges";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The lines above a holder table in text reports (`holders`, `insider`,
|
|
6
|
+
* `13f`, `fn HDS`): which listing, in which unit, and how much of the list
|
|
7
|
+
* is shown. Holder lists come as the source's own top holders, usually
|
|
8
|
+
* without a total, so the count says that rather than implying a full list.
|
|
9
|
+
*/
|
|
10
|
+
export interface HolderReportFacts {
|
|
11
|
+
name?: string | null;
|
|
12
|
+
/** Left out when the report title already names it. */
|
|
13
|
+
symbol?: string | null;
|
|
14
|
+
exchange?: string | null;
|
|
15
|
+
currency?: string | null;
|
|
16
|
+
/** Left out when the report's closing line already carries it. */
|
|
17
|
+
asOf?: string | null;
|
|
18
|
+
/** Rows printed. */
|
|
19
|
+
shown: number;
|
|
20
|
+
/** Rows the source returned, before any limit. */
|
|
21
|
+
reported: number;
|
|
22
|
+
/** Every holder the source counts, when it says so. */
|
|
23
|
+
total?: number | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** "Value (GBp)": a money column names its unit. */
|
|
27
|
+
export function moneyColumnHeader(label: string, currency?: string | null): string {
|
|
28
|
+
const unit = currency?.trim();
|
|
29
|
+
return unit ? `${label} (${unit})` : label;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function holderCountText(shown: number, reported: number, total?: number | null): string {
|
|
33
|
+
if (total != null && Number.isFinite(total) && total >= reported) {
|
|
34
|
+
return `${shown.toLocaleString("en-US")} of ${total.toLocaleString("en-US")} holders`;
|
|
35
|
+
}
|
|
36
|
+
if (reported === 0) return "none reported";
|
|
37
|
+
// Without a total the source's list is its largest holders, cut where it cuts it.
|
|
38
|
+
return shown < reported ? `${shown} of top ${reported} reported` : `top ${reported} reported`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** A venue the app knows by its short name (NasdaqGS is NASDAQ); any other as the source wrote it. */
|
|
42
|
+
function venueLabel(exchange?: string | null): string {
|
|
43
|
+
const canonical = canonicalExchange(exchange ?? "");
|
|
44
|
+
return resolveExchangeTimeZone(canonical) ? canonical : (exchange ?? "").trim();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** What the list is, after the listing is named: its unit, date and how much of it is shown. */
|
|
48
|
+
export function holderListFacts(
|
|
49
|
+
facts: Pick<HolderReportFacts, "currency" | "asOf" | "shown" | "reported" | "total">,
|
|
50
|
+
): string[] {
|
|
51
|
+
return [
|
|
52
|
+
currencyUnitLabel(facts.currency),
|
|
53
|
+
facts.asOf ? `as of ${facts.asOf}` : "",
|
|
54
|
+
holderCountText(facts.shown, facts.reported, facts.total),
|
|
55
|
+
].filter(Boolean);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function holdersHeaderLine(facts: HolderReportFacts): string {
|
|
59
|
+
const name = facts.name?.trim();
|
|
60
|
+
const symbol = facts.symbol?.trim();
|
|
61
|
+
const identity = name && symbol && name !== symbol ? `${name} (${symbol})` : name || symbol || "";
|
|
62
|
+
return [identity, venueLabel(facts.exchange), ...holderListFacts(facts)].filter(Boolean).join(" | ");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The one report date every row shares, or null when they differ or none has one. */
|
|
66
|
+
export function sharedReportDate(rows: ReadonlyArray<{ reportDate?: unknown }>): string | null {
|
|
67
|
+
const dates = new Set(rows.map((row) => (typeof row.reportDate === "string" ? row.reportDate : "")));
|
|
68
|
+
const [only] = dates;
|
|
69
|
+
return dates.size === 1 && only ? only : null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** How a holder value was reached: reported shares times a current price, not the filing's own value. */
|
|
73
|
+
export function holderValueBasis(reportDate: string | null): string {
|
|
74
|
+
return `shares reported${reportDate ? ` at ${reportDate}` : ""} x latest price`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** A listing outside the US, by its venue, or by a currency other than the dollar. */
|
|
78
|
+
function isNonUsHolderListing(exchange?: string | null, currency?: string | null): boolean {
|
|
79
|
+
const venue = canonicalExchange(exchange ?? "");
|
|
80
|
+
if (venue && !isUsListingExchange(venue) && resolveExchangeTimeZone(venue)) return true;
|
|
81
|
+
const unit = resolveCurrencyUnit(currency).currency;
|
|
82
|
+
return unit !== "" && unit !== "USD";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Holder lists are institutions' quarterly filings, mostly US 13F. On a
|
|
87
|
+
* listing outside the US they are not that market's share register, which a
|
|
88
|
+
* reader would otherwise assume.
|
|
89
|
+
*/
|
|
90
|
+
export function nonUsHolderCaveat(exchange?: string | null, currency?: string | null): string | null {
|
|
91
|
+
if (!isNonUsHolderListing(exchange, currency)) return null;
|
|
92
|
+
const canonical = canonicalExchange(exchange ?? "");
|
|
93
|
+
const venue = resolveExchangeTimeZone(canonical) ? canonical : "local";
|
|
94
|
+
return `Positions come from institutional filings (mostly US 13F), not the ${venue} share register.`;
|
|
95
|
+
}
|
|
@@ -11,8 +11,15 @@ export const DEFAULT_SORT: SortPreference = {
|
|
|
11
11
|
export const VIEW_TABS: Array<{ label: string; value: ViewMode }> = [
|
|
12
12
|
{ label: "Table", value: "table" },
|
|
13
13
|
{ label: "Chart", value: "chart" },
|
|
14
|
+
{ label: "13D/G", value: "13dg" },
|
|
14
15
|
];
|
|
15
16
|
|
|
17
|
+
/** `s` steps through the views in tab order. */
|
|
18
|
+
export function nextViewMode(current: ViewMode): ViewMode {
|
|
19
|
+
const index = VIEW_TABS.findIndex((tab) => tab.value === current);
|
|
20
|
+
return VIEW_TABS[(index + 1) % VIEW_TABS.length]!.value;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
export function buildRows(data: HolderData | null): HolderRow[] {
|
|
17
24
|
return (data?.holders ?? []).map((holder, index) => ({
|
|
18
25
|
...holder,
|
|
@@ -20,23 +27,31 @@ export function buildRows(data: HolderData | null): HolderRow[] {
|
|
|
20
27
|
}));
|
|
21
28
|
}
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
/** Whether any holder carries the quarter's change; many sources report none. */
|
|
31
|
+
export function hasHolderChanges(rows: readonly HolderRow[]): boolean {
|
|
32
|
+
return rows.some((row) => row.changeShares != null || row.changePercent != null);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function buildColumns(width: number, showChange: boolean): HolderColumn[] {
|
|
24
36
|
const valueWidth = 10;
|
|
25
37
|
const sharesWidth = 10;
|
|
26
38
|
const changeWidth = 10;
|
|
27
39
|
const changePercentWidth = 8;
|
|
28
40
|
const heldWidth = 7;
|
|
29
41
|
const dateWidth = 10;
|
|
30
|
-
const columnCount = 7;
|
|
31
|
-
const fixedWidth = valueWidth + sharesWidth +
|
|
42
|
+
const columnCount = showChange ? 7 : 5;
|
|
43
|
+
const fixedWidth = valueWidth + sharesWidth + heldWidth + dateWidth
|
|
44
|
+
+ (showChange ? changeWidth + changePercentWidth : 0);
|
|
32
45
|
const holderWidth = Math.max(16, width - 2 - columnCount - fixedWidth);
|
|
33
46
|
|
|
34
47
|
return [
|
|
35
48
|
{ id: "holder", label: "HOLDER", width: holderWidth, align: "left" },
|
|
36
49
|
{ id: "value", label: "MKT VAL", width: valueWidth, align: "right" },
|
|
37
50
|
{ id: "shares", label: "AMOUNT", width: sharesWidth, align: "right" },
|
|
38
|
-
|
|
39
|
-
|
|
51
|
+
...(showChange ? [
|
|
52
|
+
{ id: "changeShares", label: "CHG", width: changeWidth, align: "right" },
|
|
53
|
+
{ id: "changePercent", label: "CHG%", width: changePercentWidth, align: "right" },
|
|
54
|
+
] satisfies HolderColumn[] : []),
|
|
40
55
|
{ id: "percentHeld", label: "HELD", width: heldWidth, align: "right" },
|
|
41
56
|
{ id: "reportDate", label: "PERIOD", width: dateWidth, align: "right" },
|
|
42
57
|
];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { listThirteenFForms, searchThirteenFFunds } from "../thirteenf/api";
|
|
1
|
+
import { listThirteenFForms, normalizeCik, searchThirteenFFunds } from "../thirteenf/api";
|
|
2
2
|
import { isoDateToday, isoDateYearsAgo } from "../../../utils/calendar-date";
|
|
3
3
|
import { buildPeriodReports } from "../thirteenf/model";
|
|
4
4
|
import type { HolderRow } from "./types";
|
|
@@ -42,6 +42,34 @@ export function bestFundMatch(holderName: string, funds: Array<{ cik: string; na
|
|
|
42
42
|
return matches.length === 1 ? matches[0] : undefined;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* The 13F holder row that is a 13D/13G filer: the row whose matched 13F
|
|
47
|
+
* manager has the filer's CIK, else the one row whose name is the filer's once
|
|
48
|
+
* normalised. A parent or subsidiary with a longer name is not the filer, and
|
|
49
|
+
* two rows with the filer's name leave it unmatched. A manager's CIK can
|
|
50
|
+
* change (BlackRock's 13G filer did in 2024) while its 13F match keeps the
|
|
51
|
+
* old one, so an exact name is not overruled by a CIK.
|
|
52
|
+
*/
|
|
53
|
+
export function matchFilerToHolder<Row extends { id: string; name: string }>(
|
|
54
|
+
filer: { filerCik: string | null; filerName: string },
|
|
55
|
+
rows: readonly Row[],
|
|
56
|
+
fundMatches: ReadonlyMap<string, Pick<Holder13FMatch, "cik">> = new Map(),
|
|
57
|
+
): Row | undefined {
|
|
58
|
+
const cik = filer.filerCik ? normalizeCik(filer.filerCik) : null;
|
|
59
|
+
const matchedCik = (row: Row) => {
|
|
60
|
+
const match = fundMatches.get(row.id);
|
|
61
|
+
return match ? normalizeCik(match.cik) : null;
|
|
62
|
+
};
|
|
63
|
+
if (cik) {
|
|
64
|
+
const byCik = rows.filter((row) => matchedCik(row) === cik);
|
|
65
|
+
if (byCik.length === 1) return byCik[0];
|
|
66
|
+
}
|
|
67
|
+
const name = normalizeName(filer.filerName);
|
|
68
|
+
if (!name) return undefined;
|
|
69
|
+
const byName = rows.filter((row) => normalizeName(row.name) === name);
|
|
70
|
+
return byName.length === 1 ? byName[0] : undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
45
73
|
export async function loadHolder13FMatches(
|
|
46
74
|
rows: HolderRow[],
|
|
47
75
|
signal: AbortSignal,
|
|
@@ -2,7 +2,8 @@ import type { DataTableColumn } from "../../../components";
|
|
|
2
2
|
import type { HolderRecord } from "../../../types/financials";
|
|
3
3
|
import type { SortDirection } from "../../../utils/sort-values";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/** `13dg`: the Schedule 13D and 13G beneficial owners. */
|
|
6
|
+
export type ViewMode = "table" | "chart" | "13dg";
|
|
6
7
|
export type HolderColumnId = "holder" | "value" | "shares" | "changeShares" | "changePercent" | "percentHeld" | "reportDate";
|
|
7
8
|
export type HolderColumn = DataTableColumn & { id: HolderColumnId };
|
|
8
9
|
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from "./model";
|
|
18
18
|
import { relevantInsiderAmendments } from "./amendments";
|
|
19
19
|
import { formatInsiderName } from "./display";
|
|
20
|
+
import { SEC_FILINGS } from "../shared/report-freshness";
|
|
20
21
|
|
|
21
22
|
const INSIDER_COLUMNS: HeadlessPaneColumn[] = [
|
|
22
23
|
{ key: "form", header: "Form" },
|
|
@@ -84,6 +85,7 @@ export function createInsiderHeadless(
|
|
|
84
85
|
): HeadlessPaneDefinition<"rows"> {
|
|
85
86
|
return {
|
|
86
87
|
shape: "rows",
|
|
88
|
+
freshness: { ...SEC_FILINGS, basis: "Form 4 filings", observedKey: "filingDate" },
|
|
87
89
|
argument: {
|
|
88
90
|
kind: "ticker",
|
|
89
91
|
placeholder: "ticker",
|
|
@@ -104,6 +104,7 @@ function projectIpoCalendarHeadless(payload: IpoCalendarPayload, args: HeadlessP
|
|
|
104
104
|
|
|
105
105
|
export const ipoCalendarHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
106
106
|
shape: "rows",
|
|
107
|
+
freshness: { source: "Exchange listings", status: "not-a-feed", basis: "calendar" },
|
|
107
108
|
argument: {
|
|
108
109
|
kind: "free-text",
|
|
109
110
|
placeholder: "company or ticker",
|
|
@@ -11,6 +11,7 @@ const percent = (value: unknown) => typeof value === "number" ? formatVol(value)
|
|
|
11
11
|
|
|
12
12
|
export const ivHistoryHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
13
13
|
shape: "bundle", argument: { kind: "ticker", description: "US option underlying" },
|
|
14
|
+
freshness: { status: "not-a-feed", basis: "daily implied volatility", cadence: "daily", observedKey: "date", oldest: null },
|
|
14
15
|
describe: (args) => `HIVG ${args.symbols[0] ?? ""}`,
|
|
15
16
|
discovery: { aliases: ["HIVG"], screenshotReadiness: "live-dom", dataRequirements: ["Cloud stored implied volatility", "Daily price history"],
|
|
16
17
|
limitations: ["History starts February 2024 (OPRA daily trade closes)", "Rank and percentile use trade-close readings only"] },
|
|
@@ -57,6 +58,7 @@ export const ivHistoryHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
57
58
|
|
|
58
59
|
export const ivScreenHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
59
60
|
shape: "bundle",
|
|
61
|
+
freshness: { status: "not-a-feed", basis: "daily implied volatility", cadence: "daily" },
|
|
60
62
|
argument: { kind: "symbol-list", optional: true, maximum: VCA_LIMIT, description: "US option underlyings; defaults to index and sector ETFs." },
|
|
61
63
|
options: [{ key: "preset", type: "enum", values: [{ value: "etfs" }, { value: "megacaps" }], defaultValue: "etfs", description: "Preset when no symbols are given" }],
|
|
62
64
|
describe: "Volatility rich/cheap",
|
|
@@ -86,7 +88,8 @@ export const ivScreenHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
86
88
|
{ key: "ivHv", header: "IV/HV", format: (value: unknown) => typeof value === "number" ? value.toFixed(2) : "--" },
|
|
87
89
|
], rows: rows.map((row) => ({ ...row })) }],
|
|
88
90
|
complete: !queued.length && !universe.error, unavailableSymbols: queued,
|
|
89
|
-
errors: [universe.error
|
|
91
|
+
errors: [universe.error].filter((value): value is string => !!value),
|
|
92
|
+
...(queued.length ? { notes: [`Queued for backfill: ${queued.join(", ")}.`] } : {}),
|
|
90
93
|
metadata: { asOf: payload.asOf, presets: VCA_PRESETS, methodology: METHODOLOGY },
|
|
91
94
|
};
|
|
92
95
|
},
|
|
@@ -151,6 +151,7 @@ function companyBundle(symbol: string, state: JobsCompanyState, roleLimit: numbe
|
|
|
151
151
|
*/
|
|
152
152
|
export const jobsHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
153
153
|
shape: "bundle",
|
|
154
|
+
freshness: { source: "Company careers sites", status: "not-a-feed", basis: "observed job postings" },
|
|
154
155
|
argument: {
|
|
155
156
|
kind: "ticker",
|
|
156
157
|
placeholder: "ticker",
|
|
@@ -15,6 +15,7 @@ export const positionSizerModule: PluginModule = {
|
|
|
15
15
|
panes: [
|
|
16
16
|
{
|
|
17
17
|
id: KELLY_PANE_ID,
|
|
18
|
+
reportFreshness: { source: "Your inputs and Gloom Cloud", status: "not-a-feed", basis: "position sizing" },
|
|
18
19
|
name: "Position Sizer",
|
|
19
20
|
icon: "K",
|
|
20
21
|
component: KellySizerPane,
|
|
@@ -11,6 +11,8 @@ const share = (value: unknown) => typeof value === "number" ? `${Math.round(valu
|
|
|
11
11
|
|
|
12
12
|
export const macroDayHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
13
13
|
shape: "bundle", argument: { kind: "ticker", description: "Ticker" },
|
|
14
|
+
// Dated by the maintained release list as much as by the closes, so no session schedule applies.
|
|
15
|
+
freshness: { status: "not-a-feed", basis: "release-day study on daily closes" },
|
|
14
16
|
describe: (args) => `MDAY ${args.symbols[0] ?? ""}`,
|
|
15
17
|
discovery: { screenshotReadiness: "live-dom", limitations: [
|
|
16
18
|
"US listings; close-to-close on the release day.",
|
|
@@ -6,6 +6,8 @@ export const MARKET_HEATMAP_UNIVERSES = [
|
|
|
6
6
|
{ id: "us-equity", label: "US Stocks" },
|
|
7
7
|
{ id: "us-etf", label: "US ETFs" },
|
|
8
8
|
] as const;
|
|
9
|
+
/** The 500 largest US stocks (an older server answers with its own maximum); ETFs stay flat and need fewer. */
|
|
10
|
+
export const MARKET_HEATMAP_REQUEST_COUNT: Record<MarketHeatmapUniverseId, number> = { "us-equity": 500, "us-etf": 160 };
|
|
9
11
|
export interface MarketHeatmapFetchOptions { count?: number; forceRefresh?: boolean; cache?: boolean; }
|
|
10
12
|
export interface MarketHeatmapSources { client?: Pick<typeof apiClient, "getMarketHeatmap">; }
|
|
11
13
|
const DEFAULT_COUNT = 80;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { HeadlessPaneColumn, HeadlessPaneDefinition } from "../../../types/plugin";
|
|
2
|
+
import { formatCompact, formatPercentRaw } from "../../../utils/format";
|
|
3
|
+
import { MARKET_HEATMAP_REQUEST_COUNT, MARKET_HEATMAP_UNIVERSES, fetchMarketHeatmap, type MarketHeatmapUniverseId } from "./data";
|
|
4
|
+
import { heatmapMove, summarizeHeatmapGroups, type HeatmapGroupBy, type HeatmapGroupSummary } from "./model";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A few names always lack a move (foreign listings and new tickers the snapshot
|
|
8
|
+
* has no change for). They are listed in a notice and in `metadata.noMove`; the
|
|
9
|
+
* report is incomplete only when so many lack one that the groups mislead.
|
|
10
|
+
*/
|
|
11
|
+
const MIN_MOVE_COVERAGE = 0.9;
|
|
12
|
+
|
|
13
|
+
const percent = (value: unknown) => typeof value === "number" ? formatPercentRaw(value) : "—";
|
|
14
|
+
const share = (value: unknown) => typeof value === "number" ? `${value.toFixed(1)}%` : "—";
|
|
15
|
+
const dollars = (value: unknown) => typeof value === "number" && value > 0 ? `$${formatCompact(value)}` : "—";
|
|
16
|
+
const member = (symbol: unknown, move: unknown) => typeof symbol === "string" && typeof move === "number"
|
|
17
|
+
? `${symbol} ${formatPercentRaw(move)}`
|
|
18
|
+
: "—";
|
|
19
|
+
|
|
20
|
+
function columns(universe: MarketHeatmapUniverseId, groupBy: HeatmapGroupBy, flat: boolean): HeadlessPaneColumn[] {
|
|
21
|
+
return [
|
|
22
|
+
...(flat ? [] : groupBy === "industry"
|
|
23
|
+
? [{ key: "group", header: "Industry" }, { key: "sector", header: "Sector" }]
|
|
24
|
+
: [{ key: "group", header: "Sector" }]),
|
|
25
|
+
{ key: "names", header: "Names", align: "right" },
|
|
26
|
+
{ key: "size", header: universe === "us-etf" ? "Net assets" : "Mkt cap", align: "right", format: dollars },
|
|
27
|
+
...(flat ? [] : [{ key: "sharePercent", header: "Share", align: "right" as const, format: share }]),
|
|
28
|
+
{ key: "move", header: universe === "us-etf" ? "Move (asset-wtd)" : "Move (cap-wtd)", align: "right", format: percent },
|
|
29
|
+
{ key: "up", header: "Up", align: "right" },
|
|
30
|
+
{ key: "down", header: "Down", align: "right" },
|
|
31
|
+
{ key: "bestSymbol", header: "Best", format: (value, row) => member(value, row.bestMove) },
|
|
32
|
+
{ key: "worstSymbol", header: "Worst", format: (value, row) => member(value, row.worstMove) },
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function noMoveNotice(symbols: readonly string[], names: number): string {
|
|
37
|
+
const shown = symbols.slice(0, 8).join(", ");
|
|
38
|
+
const rest = symbols.length > 8 ? ` and ${symbols.length - 8} more` : "";
|
|
39
|
+
return `${symbols.length} of ${names} names have no move yet and count toward size only: ${shown}${rest}.`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function projectRow(summary: HeatmapGroupSummary, groupBy: HeatmapGroupBy, whole = false) {
|
|
43
|
+
return {
|
|
44
|
+
group: whole ? "All" : summary.group ?? (summary.sector ? "No industry" : groupBy === "industry" ? "Unclassified" : "No sector"),
|
|
45
|
+
...(groupBy === "industry" ? { sector: summary.sector ?? "—" } : {}),
|
|
46
|
+
names: summary.names,
|
|
47
|
+
size: summary.size,
|
|
48
|
+
sharePercent: summary.share * 100,
|
|
49
|
+
move: summary.move,
|
|
50
|
+
moved: summary.moved,
|
|
51
|
+
up: summary.up,
|
|
52
|
+
down: summary.down,
|
|
53
|
+
unchanged: summary.unchanged,
|
|
54
|
+
bestSymbol: summary.best?.symbol ?? null,
|
|
55
|
+
bestMove: summary.best?.move ?? null,
|
|
56
|
+
worstSymbol: summary.worst?.symbol ?? null,
|
|
57
|
+
worstMove: summary.worst?.move ?? null,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const marketHeatmapHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
62
|
+
shape: "rows",
|
|
63
|
+
description: "The heat map's sectors or industries: each group's size-weighted day move, how many names rose and fell, and its best and worst name, for the 500 largest US stocks or large US ETFs.",
|
|
64
|
+
argument: { kind: "none" },
|
|
65
|
+
options: [
|
|
66
|
+
{
|
|
67
|
+
key: "universe",
|
|
68
|
+
description: "Board: the 500 largest US stocks, or large US ETFs (one group, as the ETF map has no sectors).",
|
|
69
|
+
type: "enum",
|
|
70
|
+
values: [
|
|
71
|
+
{ value: "us-equity", aliases: ["stocks", "equity", "us"] },
|
|
72
|
+
{ value: "us-etf", aliases: ["etf", "etfs"] },
|
|
73
|
+
],
|
|
74
|
+
defaultValue: "us-equity",
|
|
75
|
+
settingKey: "universe",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: "group",
|
|
79
|
+
description: "Group the stocks by sector, or by industry within each sector.",
|
|
80
|
+
type: "enum",
|
|
81
|
+
values: [{ value: "sector", aliases: ["sectors"] }, { value: "industry", aliases: ["industries"] }],
|
|
82
|
+
defaultValue: "sector",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
discovery: {
|
|
86
|
+
aliases: ["HM", "heatmap"],
|
|
87
|
+
dataRequirements: ["Gloom Cloud market heatmap snapshot"],
|
|
88
|
+
limitations: [
|
|
89
|
+
"The snapshot the pane starts from, refreshed about once a minute; the pane's live-streamed colors are not in the report",
|
|
90
|
+
"Moves are weighted by market cap (net assets for ETFs), not by the pane's square-root tile area",
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
// A board snapshot refreshed on a schedule, not a feed; the pane streams on top of it, the report does not.
|
|
94
|
+
freshness: { status: "delayed" },
|
|
95
|
+
describe: (args) => {
|
|
96
|
+
const universe = MARKET_HEATMAP_UNIVERSES.find((entry) => entry.id === args.options.universe)?.label ?? "US Stocks";
|
|
97
|
+
return args.options.universe === "us-etf" ? `Market Heatmap | ${universe}` : `Market Heatmap | ${universe} by ${String(args.options.group)}`;
|
|
98
|
+
},
|
|
99
|
+
async load(args, ctx) {
|
|
100
|
+
const universe: MarketHeatmapUniverseId = args.options.universe === "us-etf" ? "us-etf" : "us-equity";
|
|
101
|
+
const groupBy: HeatmapGroupBy = args.options.group === "industry" ? "industry" : "sector";
|
|
102
|
+
const result = await fetchMarketHeatmap(
|
|
103
|
+
universe,
|
|
104
|
+
{ count: MARKET_HEATMAP_REQUEST_COUNT[universe], forceRefresh: ctx.refresh },
|
|
105
|
+
{ client: ctx.apiClient },
|
|
106
|
+
);
|
|
107
|
+
ctx.signal.throwIfAborted();
|
|
108
|
+
const { grouping, groups, board } = summarizeHeatmapGroups(result.assets, groupBy);
|
|
109
|
+
const flat = grouping === "flat";
|
|
110
|
+
const noMove = result.assets.filter((asset) => heatmapMove(asset) == null).map((asset) => asset.symbol);
|
|
111
|
+
const covered = result.assets.length > 0 && board.moved / board.names >= MIN_MOVE_COVERAGE;
|
|
112
|
+
return {
|
|
113
|
+
columns: columns(universe, groupBy, flat),
|
|
114
|
+
rows: groups.map((summary) => projectRow(summary, groupBy, flat)),
|
|
115
|
+
complete: !result.stale && covered,
|
|
116
|
+
unavailableSymbols: covered ? [] : noMove,
|
|
117
|
+
metadata: {
|
|
118
|
+
universe,
|
|
119
|
+
groupBy: flat ? null : groupBy,
|
|
120
|
+
asOf: new Date(result.fetchedAt).toISOString(),
|
|
121
|
+
stale: result.stale === true,
|
|
122
|
+
session: result.session ?? null,
|
|
123
|
+
regularSessionDate: result.regularSessionDate ?? null,
|
|
124
|
+
names: result.assets.length,
|
|
125
|
+
noMove,
|
|
126
|
+
...(noMove.length > 0 ? { notices: [noMoveNotice(noMove, result.assets.length)] } : {}),
|
|
127
|
+
board: projectRow(board, groupBy, true),
|
|
128
|
+
unit: "move and sharePercent in percent; size in USD",
|
|
129
|
+
weighting: universe === "us-etf"
|
|
130
|
+
? "Each group's move is its names' day moves weighted by net assets, over the names with a move."
|
|
131
|
+
: "Each group's move is its names' day moves weighted by market cap, over the names with a move.",
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
};
|
|
@@ -29,7 +29,7 @@ import { t, tf } from "../../../i18n";
|
|
|
29
29
|
import { priceColor } from "../../../theme/colors";
|
|
30
30
|
import { clipToDisplayWidth, formatCompact, formatCurrency, formatPercentRaw } from "../../../utils/format";
|
|
31
31
|
import { isPlainKey } from "../../../utils/keyboard";
|
|
32
|
-
import { useAppSelector, usePaneAppConfig, usePaneSettingValue } from "../../../state/app/context";
|
|
32
|
+
import { useAppSelector, usePaneAppConfig, usePaneSettingValue, usePaneStateValue } from "../../../state/app/context";
|
|
33
33
|
import { usePluginTickerActions } from "../../runtime";
|
|
34
34
|
import { useLiveQuoteEntries } from "../../../state/hooks/quote-streaming";
|
|
35
35
|
import { useFxRatesMap, useTickerFinancialsMap } from "../../../market-data/hooks";
|
|
@@ -44,18 +44,21 @@ import { resolvePortfolioTotalsCurrency } from "../portfolio-list/metrics";
|
|
|
44
44
|
import { useThrottledMemo } from "../portfolio-list/use-throttled-memo";
|
|
45
45
|
import { PORTFOLIO_REORDER_THROTTLE_MS } from "../portfolio-list/use-throttled-ticker-order";
|
|
46
46
|
import {
|
|
47
|
+
MARKET_HEATMAP_REQUEST_COUNT,
|
|
47
48
|
MARKET_HEATMAP_UNIVERSES,
|
|
48
49
|
fetchMarketHeatmap,
|
|
49
50
|
resetMarketHeatmapCache,
|
|
50
51
|
type MarketHeatmapUniverseId,
|
|
51
52
|
} from "./data";
|
|
52
53
|
import {
|
|
54
|
+
HEATMAP_COLLECTION_KIND_STATE_KEY,
|
|
53
55
|
PORTFOLIO_HEATMAP_TAB,
|
|
54
56
|
buildPortfolioHeatmapAssets,
|
|
55
57
|
fallbackHeatmapCollectionId,
|
|
56
58
|
heatmapCollectionLabel,
|
|
57
59
|
heatmapFollowsCollection,
|
|
58
60
|
heatmapSizeBy,
|
|
61
|
+
heatmapSizeByApplies,
|
|
59
62
|
heatmapSizeWeight,
|
|
60
63
|
heatmapTabId,
|
|
61
64
|
isRemoteHeatmapUniverse,
|
|
@@ -76,6 +79,8 @@ import {
|
|
|
76
79
|
rankHeatmapQuoteWeights,
|
|
77
80
|
useSettledValue,
|
|
78
81
|
} from "./live";
|
|
82
|
+
import { marketHeatmapHeadless } from "./headless";
|
|
83
|
+
import { heatmapMove, resolveHeatmapGrouping, sizeWeightedMove, type HeatmapGrouping } from "./model";
|
|
79
84
|
import {
|
|
80
85
|
overlayScreenerQuoteEntries,
|
|
81
86
|
resolveScreenerQuoteFeedStatus,
|
|
@@ -83,8 +88,6 @@ import {
|
|
|
83
88
|
|
|
84
89
|
const NO_ASSETS: HeatmapBoardAsset[] = [];
|
|
85
90
|
const NO_TARGETS: QuoteSubscriptionTarget[] = [];
|
|
86
|
-
/** The 500 largest US stocks (an older server answers with its own maximum); ETFs stay flat and need fewer. */
|
|
87
|
-
const MARKET_HEATMAP_REQUEST_COUNT: Record<MarketHeatmapUniverseId, number> = { "us-equity": 500, "us-etf": 160 };
|
|
88
91
|
const SNAPSHOT_REFRESH_MS = 60_000;
|
|
89
92
|
const LAYOUT_THROTTLE_MS = 5_000;
|
|
90
93
|
/** A size change below this share of a tile's area is not worth moving it. */
|
|
@@ -128,34 +131,16 @@ function sizeLabel(asset: HeatmapBoardAsset): string | null {
|
|
|
128
131
|
return `${label} ${formatMoneyCompact(asset.size, asset.sizeCurrency ?? asset.currency)}`;
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
/**
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
/** Marks a pre-market or after-hours move, which is measured from the regular close. */
|
|
135
|
+
function sessionMark(asset: HeatmapBoardAsset): string | null {
|
|
136
|
+
if (asset.extendedSession === "PRE") return "PM";
|
|
137
|
+
if (asset.extendedSession === "POST") return "AH";
|
|
138
|
+
return null;
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
* Sector and industry blocks when the board knows its sectors. A board where
|
|
142
|
-
* most of the value has none (ETFs, or a snapshot whose classification
|
|
143
|
-
* failed) lays out flat rather than as one big unlabeled block.
|
|
144
|
-
*/
|
|
145
|
-
function resolveGrouping(assets: readonly HeatmapBoardAsset[], industries: boolean): HeatmapGrouping {
|
|
146
|
-
let total = 0;
|
|
147
|
-
let classified = 0;
|
|
148
|
-
const sectors = new Set<string>();
|
|
149
|
-
for (const asset of assets) {
|
|
150
|
-
const weight = asset.weight ?? asset.size ?? 0;
|
|
151
|
-
total += weight;
|
|
152
|
-
if (asset.sector) {
|
|
153
|
-
classified += weight;
|
|
154
|
-
sectors.add(asset.sector);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (sectors.size < 2 || classified < total / 2) return "flat";
|
|
158
|
-
return industries ? "sector-industry" : "sector";
|
|
141
|
+
function formatMove(asset: HeatmapBoardAsset, change: number | null): string {
|
|
142
|
+
const mark = sessionMark(asset);
|
|
143
|
+
return change == null ? "—" : mark ? `${formatPercentRaw(change)} ${mark}` : formatPercentRaw(change);
|
|
159
144
|
}
|
|
160
145
|
|
|
161
146
|
/**
|
|
@@ -191,7 +176,7 @@ const paintItemCache = new WeakMap<HeatmapBoardAsset, MetricTreemapItem<HeatmapB
|
|
|
191
176
|
function paintItem(asset: HeatmapBoardAsset): MetricTreemapItem<HeatmapBoardAsset> {
|
|
192
177
|
const cached = paintItemCache.get(asset);
|
|
193
178
|
if (cached) return cached;
|
|
194
|
-
const change =
|
|
179
|
+
const change = heatmapMove(asset);
|
|
195
180
|
const details = [
|
|
196
181
|
asset.price > 0 ? formatCurrency(asset.price, asset.currency) : null,
|
|
197
182
|
sizeLabel(asset),
|
|
@@ -205,8 +190,9 @@ function paintItem(asset: HeatmapBoardAsset): MetricTreemapItem<HeatmapBoardAsse
|
|
|
205
190
|
weight: asset.weight ?? asset.size ?? 0,
|
|
206
191
|
colorValue: change,
|
|
207
192
|
primaryText: formatHeatTileMove(change),
|
|
193
|
+
primaryTextSuffix: sessionMark(asset),
|
|
208
194
|
tooltip: [
|
|
209
|
-
[asset.symbol, name,
|
|
195
|
+
[asset.symbol, name, formatMove(asset, change)].filter(Boolean).join(" · "),
|
|
210
196
|
...(details.length > 0 ? [details.join(" · ")] : []),
|
|
211
197
|
],
|
|
212
198
|
data: asset,
|
|
@@ -224,18 +210,10 @@ function otherSummary(items: readonly MetricTreemapItem<HeatmapBoardAsset>[]): s
|
|
|
224
210
|
}
|
|
225
211
|
|
|
226
212
|
function otherTooltip(items: readonly MetricTreemapItem<HeatmapBoardAsset>[]): string[] {
|
|
227
|
-
|
|
228
|
-
let weightedMove = 0;
|
|
229
|
-
for (const item of items) {
|
|
230
|
-
const change = changeOf(item.data);
|
|
231
|
-
const size = item.data.size ?? 0;
|
|
232
|
-
if (change == null || !(size > 0)) continue;
|
|
233
|
-
weight += size;
|
|
234
|
-
weightedMove += change * size;
|
|
235
|
-
}
|
|
213
|
+
const move = sizeWeightedMove(items.map((item) => item.data));
|
|
236
214
|
return [
|
|
237
215
|
tf("Other · {count} smaller names", { count: items.length }),
|
|
238
|
-
...(
|
|
216
|
+
...(move != null ? [`${formatPercentRaw(move)} ${t("cap-weighted")}`] : []),
|
|
239
217
|
];
|
|
240
218
|
}
|
|
241
219
|
|
|
@@ -262,6 +240,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
262
240
|
const linkedPortfolio = useLinkedHeatmapCollection();
|
|
263
241
|
const collectionId = linkedPortfolio.collectionId ?? fallbackHeatmapCollectionId(config);
|
|
264
242
|
const collectionKind = getCollectionTypeFromConfig(config, collectionId);
|
|
243
|
+
const [, publishCollectionKind] = usePaneStateValue<string>(HEATMAP_COLLECTION_KIND_STATE_KEY, "");
|
|
265
244
|
const portfolioLabel = heatmapCollectionLabel(config, collectionId);
|
|
266
245
|
const universeTabs = useMemo(() => [
|
|
267
246
|
...MARKET_HEATMAP_UNIVERSES.map((universe) => ({ label: universe.label, value: universe.id })),
|
|
@@ -367,7 +346,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
367
346
|
liveStreaming,
|
|
368
347
|
});
|
|
369
348
|
const resolvedAssets = useMemo(
|
|
370
|
-
() => overlayScreenerQuoteEntries(boardAssets, liveQuoteEntries),
|
|
349
|
+
() => overlayScreenerQuoteEntries(boardAssets, liveQuoteEntries, { extendedSessions: true }),
|
|
371
350
|
[boardAssets, liveQuoteEntries],
|
|
372
351
|
);
|
|
373
352
|
const feedStatus = useMemo(
|
|
@@ -381,7 +360,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
381
360
|
// Sizes follow live prices at most every LAYOUT_THROTTLE_MS and only past
|
|
382
361
|
// LAYOUT_TOLERANCE; a new snapshot relays out at once. Ticks only recolour.
|
|
383
362
|
const grouping = useMemo(
|
|
384
|
-
() =>
|
|
363
|
+
() => resolveHeatmapGrouping(boardAssets, activeUniverse === "us-equity"),
|
|
385
364
|
[activeUniverse, boardAssets],
|
|
386
365
|
);
|
|
387
366
|
const layoutAssets = useThrottledMemo(
|
|
@@ -456,6 +435,11 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
456
435
|
setSelectedSymbol(null);
|
|
457
436
|
}, [collectionId, linkPortfolio, setActiveUniverse]);
|
|
458
437
|
|
|
438
|
+
// The header shows the square-root control only where it changes the board.
|
|
439
|
+
useEffect(() => {
|
|
440
|
+
publishCollectionKind(collectionKind ?? "");
|
|
441
|
+
}, [collectionKind, publishCollectionKind]);
|
|
442
|
+
|
|
459
443
|
// The financials map only reads the cache; this fills it for the list on screen.
|
|
460
444
|
useEffect(() => {
|
|
461
445
|
if (!portfolioTab) return;
|
|
@@ -610,11 +594,12 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
610
594
|
parts: [
|
|
611
595
|
{ text: selectedAsset.symbol, tone: "label" as const },
|
|
612
596
|
{
|
|
613
|
-
text:
|
|
597
|
+
text: heatmapMove(selectedAsset) == null ? "—" : formatPercentRaw(heatmapMove(selectedAsset)!),
|
|
614
598
|
tone: "value" as const,
|
|
615
|
-
color:
|
|
599
|
+
color: heatmapMove(selectedAsset) == null ? undefined : priceColor(heatmapMove(selectedAsset)!),
|
|
616
600
|
bold: true,
|
|
617
601
|
},
|
|
602
|
+
...(sessionMark(selectedAsset) ? [{ text: sessionMark(selectedAsset)!, tone: "muted" as const }] : []),
|
|
618
603
|
...(selectedAsset.price > 0
|
|
619
604
|
? [{ text: formatCurrency(selectedAsset.price, selectedAsset.currency), tone: "value" as const }]
|
|
620
605
|
: []),
|
|
@@ -696,12 +681,20 @@ export const marketHeatmapPlugin: GloomPlugin = {
|
|
|
696
681
|
name: "Market Heatmap",
|
|
697
682
|
icon: "H",
|
|
698
683
|
component: MarketHeatmapPane,
|
|
684
|
+
headless: marketHeatmapHeadless,
|
|
699
685
|
defaultPosition: "right",
|
|
700
686
|
defaultMode: "floating",
|
|
701
687
|
defaultFloatingSize: { width: 110, height: 36 },
|
|
702
688
|
quickSettings: [
|
|
703
689
|
LIVE_STREAMING_QUICK_SETTING,
|
|
704
|
-
{
|
|
690
|
+
{
|
|
691
|
+
type: "toggle",
|
|
692
|
+
key: SIZE_BY_SETTING_KEY,
|
|
693
|
+
icon: "sqrt",
|
|
694
|
+
onValue: SQRT_SIZE_VALUE,
|
|
695
|
+
label: "Size by square root of market cap",
|
|
696
|
+
visible: (context) => heatmapSizeByApplies(context.settings.universe, context.paneState[HEATMAP_COLLECTION_KIND_STATE_KEY]),
|
|
697
|
+
},
|
|
705
698
|
],
|
|
706
699
|
settings: (context) => withLiveStreamingSetting({
|
|
707
700
|
title: "Market Heatmap Settings",
|