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
|
@@ -4,10 +4,14 @@ import {
|
|
|
4
4
|
type AccountProfile,
|
|
5
5
|
type ChatUserSummary,
|
|
6
6
|
} from "../../../api-client";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import { PROFILE_POPOVER_CLOSE_DELAY_MS } from "./message/profile-popover";
|
|
8
|
+
import type { ChatUserAnchor } from "./message/types";
|
|
9
|
+
|
|
10
|
+
interface ProfilePopoverOptions {
|
|
11
|
+
ownProfile?: boolean;
|
|
12
|
+
/** The name or @mention it opens from; the desktop places the card beside it. */
|
|
13
|
+
anchor?: ChatUserAnchor;
|
|
14
|
+
}
|
|
11
15
|
|
|
12
16
|
function accountProfileToChatUser(profile: AccountProfile): ChatUserSummary {
|
|
13
17
|
return {
|
|
@@ -39,6 +43,7 @@ function isAccountProfileConfigured(profile: AccountProfile): boolean {
|
|
|
39
43
|
|
|
40
44
|
export function useChatProfilePopover(trackOwnProfileUserId?: string) {
|
|
41
45
|
const [profilePopoverUser, setProfilePopoverUser] = useState<ChatUserSummary | null>(null);
|
|
46
|
+
const [profilePopoverAnchor, setProfilePopoverAnchor] = useState<ChatUserAnchor>(null);
|
|
42
47
|
const [ownProfileConfigured, setOwnProfileConfigured] = useState<boolean | null>(null);
|
|
43
48
|
const profilePopoverCloseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
44
49
|
const ownProfileRef = useRef<ChatUserSummary | null>(null);
|
|
@@ -60,6 +65,7 @@ export function useChatProfilePopover(trackOwnProfileUserId?: string) {
|
|
|
60
65
|
pinnedRef.current = false;
|
|
61
66
|
profilePopoverUserIdRef.current = null;
|
|
62
67
|
setProfilePopoverUser(null);
|
|
68
|
+
setProfilePopoverAnchor(null);
|
|
63
69
|
}, [cancelProfilePopoverClose]);
|
|
64
70
|
|
|
65
71
|
const scheduleProfilePopoverClose = useCallback(() => {
|
|
@@ -70,6 +76,7 @@ export function useChatProfilePopover(trackOwnProfileUserId?: string) {
|
|
|
70
76
|
if (pinnedRef.current) return;
|
|
71
77
|
profilePopoverUserIdRef.current = null;
|
|
72
78
|
setProfilePopoverUser(null);
|
|
79
|
+
setProfilePopoverAnchor(null);
|
|
73
80
|
}, PROFILE_POPOVER_CLOSE_DELAY_MS);
|
|
74
81
|
}, [cancelProfilePopoverClose]);
|
|
75
82
|
|
|
@@ -104,32 +111,29 @@ export function useChatProfilePopover(trackOwnProfileUserId?: string) {
|
|
|
104
111
|
|
|
105
112
|
const showProfilePopover = useCallback((
|
|
106
113
|
targetUser: ChatUserSummary,
|
|
107
|
-
options?:
|
|
114
|
+
options?: ProfilePopoverOptions & { pin?: boolean },
|
|
108
115
|
) => {
|
|
109
116
|
const ownProfile = options?.ownProfile === true;
|
|
110
117
|
const cachedUser = ownProfile && ownProfileRef.current?.id === targetUser.id
|
|
111
118
|
? ownProfileRef.current
|
|
112
119
|
: targetUser;
|
|
113
|
-
//
|
|
114
|
-
if (!ownProfile && !hasPublicChatProfileInfo(cachedUser)) {
|
|
115
|
-
closeProfilePopover();
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
120
|
+
// Every name has a card: a private or empty profile gets the name-only one.
|
|
118
121
|
cancelProfilePopoverClose();
|
|
119
122
|
pinnedRef.current = options?.pin === true;
|
|
120
123
|
profilePopoverUserIdRef.current = cachedUser.id;
|
|
121
124
|
setProfilePopoverUser(cachedUser);
|
|
125
|
+
setProfilePopoverAnchor(options?.anchor ?? null);
|
|
122
126
|
if (ownProfile) refreshOwnProfile(targetUser.id);
|
|
123
|
-
}, [cancelProfilePopoverClose,
|
|
127
|
+
}, [cancelProfilePopoverClose, refreshOwnProfile]);
|
|
124
128
|
|
|
125
129
|
/** Pointing at a name previews its card, but never over one a click pinned. */
|
|
126
|
-
const hoverProfilePopover = useCallback((targetUser: ChatUserSummary, options?:
|
|
130
|
+
const hoverProfilePopover = useCallback((targetUser: ChatUserSummary, options?: ProfilePopoverOptions) => {
|
|
127
131
|
if (pinnedRef.current) return;
|
|
128
132
|
showProfilePopover(targetUser, options);
|
|
129
133
|
}, [showProfilePopover]);
|
|
130
134
|
|
|
131
135
|
/** A click on a name pins its card until Esc, a click outside, or a second click. */
|
|
132
|
-
const toggleProfilePopover = useCallback((targetUser: ChatUserSummary, options?:
|
|
136
|
+
const toggleProfilePopover = useCallback((targetUser: ChatUserSummary, options?: ProfilePopoverOptions) => {
|
|
133
137
|
// The desktop card hears the same click first, as a click outside it.
|
|
134
138
|
if (dismissedPinnedUserIdRef.current === targetUser.id) {
|
|
135
139
|
dismissedPinnedUserIdRef.current = null;
|
|
@@ -177,6 +181,7 @@ export function useChatProfilePopover(trackOwnProfileUserId?: string) {
|
|
|
177
181
|
closeProfilePopover,
|
|
178
182
|
dismissProfilePopover,
|
|
179
183
|
ownProfileConfigured,
|
|
184
|
+
profilePopoverAnchor,
|
|
180
185
|
profilePopoverUser,
|
|
181
186
|
hoverProfilePopover,
|
|
182
187
|
scheduleProfilePopoverClose,
|
|
@@ -285,7 +285,8 @@ function defaultHeadlessExecutor(
|
|
|
285
285
|
return {
|
|
286
286
|
result: serializeHeadlessPaneResult(loaded.definition, result),
|
|
287
287
|
rowCount: headlessRowCount(loaded.definition, result),
|
|
288
|
-
|
|
288
|
+
// Ask Gloom reads a caveat as a partial result, so notes join the errors here.
|
|
289
|
+
...(result.errors?.length || result.notes?.length ? { errors: [...(result.errors ?? []), ...(result.notes ?? [])] } : {}),
|
|
289
290
|
};
|
|
290
291
|
};
|
|
291
292
|
}
|
|
@@ -23,6 +23,7 @@ export const teamModule: PluginModule = {
|
|
|
23
23
|
capabilities: [createCloudTeamCapability(), createCloudViewsCapability()],
|
|
24
24
|
panes: [{
|
|
25
25
|
id: TEAM_PANE_ID,
|
|
26
|
+
reportFreshness: { status: "not-a-feed", basis: "account data" },
|
|
26
27
|
name: "Team",
|
|
27
28
|
icon: "T",
|
|
28
29
|
component: TeamPane,
|
|
@@ -12,6 +12,7 @@ import { ThesisTickerTab } from "./ticker-tab";
|
|
|
12
12
|
export const thesisModule: PluginModule = {
|
|
13
13
|
panes: [{
|
|
14
14
|
id: THESIS_PANE_ID,
|
|
15
|
+
reportFreshness: { source: "Your theses", status: "not-a-feed", basis: "your theses" },
|
|
15
16
|
name: "Theses",
|
|
16
17
|
icon: "Θ",
|
|
17
18
|
component: ThesisBoardPane,
|
|
@@ -28,6 +28,7 @@ export function registerTwitterFeedFeature(ctx: GloomPluginContext): void {
|
|
|
28
28
|
|
|
29
29
|
ctx.registerPane({
|
|
30
30
|
id: TWITTER_FEED_PANE_ID,
|
|
31
|
+
reportFreshness: { source: "X posts", status: "not-a-feed", basis: "posts" },
|
|
31
32
|
name: "X Feed",
|
|
32
33
|
icon: "X",
|
|
33
34
|
component: TwitterFeedPane,
|
|
@@ -34,6 +34,7 @@ export const commentLettersPlugin: GloomPlugin = {
|
|
|
34
34
|
panes: [
|
|
35
35
|
{
|
|
36
36
|
id: COMMENT_LETTERS_PANE_ID,
|
|
37
|
+
reportFreshness: { source: "SEC EDGAR", status: "not-a-feed", basis: "comment letters" },
|
|
37
38
|
name: "Comment Letters",
|
|
38
39
|
icon: "L",
|
|
39
40
|
component: CommentLettersPane,
|
|
@@ -7,6 +7,9 @@ import { appsModel, hiringModel, type AttentionKind } from "./model";
|
|
|
7
7
|
export function attentionHeadless(kind: AttentionKind): HeadlessPaneDefinition<"bundle"> {
|
|
8
8
|
return {
|
|
9
9
|
shape: "bundle",
|
|
10
|
+
freshness: kind === "hiring"
|
|
11
|
+
? { source: "Company careers sites", status: "not-a-feed", basis: "observed job postings" }
|
|
12
|
+
: { source: "App Store and Google Play charts", status: "not-a-feed", basis: "observed chart ranks" },
|
|
10
13
|
argument: { kind: "ticker", optional: true, placeholder: "ticker", description: "Company ticker, including exchange for non-US listings. Omit for the global board." },
|
|
11
14
|
options: [
|
|
12
15
|
{ key: "limit", type: "string", defaultValue: "100", description: "Rows per REST page, up to 200 for hiring and 500 for apps." },
|
|
@@ -36,7 +39,8 @@ export function attentionHeadless(kind: AttentionKind): HeadlessPaneDefinition<"
|
|
|
36
39
|
const nextOffset = kind === "hiring" && "total" in data ? offset + data.companies.length < data.total ? offset + data.companies.length : null : (data as AppAttentionPayload).page?.nextOffset ?? null;
|
|
37
40
|
return {
|
|
38
41
|
complete: !model.preview && nextOffset === null,
|
|
39
|
-
errors: [...model.notices, ...(
|
|
42
|
+
errors: [...model.notices, ...(model.preview ? ["Additional rows and history require Gloom Pro."] : [])],
|
|
43
|
+
...(nextOffset !== null ? { notes: [`Additional observations available with --offset ${nextOffset}.`] } : {}),
|
|
40
44
|
sections: Object.entries(model.sections).map(([key, section]) => ({ title: key === "mix" ? kind === "hiring" ? "Role family" : "Countries" : key,
|
|
41
45
|
columns: section.columns.map((column) => ({ key: column.id, header: column.label, align: column.align })),
|
|
42
46
|
rows: section.rows.map((row) => ({ ...row.values, ...(row.url ? { sourceUrl: row.url } : {}), ...(row.details ? { evidence: row.details } : {}) })) })),
|
|
@@ -172,7 +172,7 @@ function AttentionView({ kind, symbol, width, height, focused }: Size & { kind:
|
|
|
172
172
|
const numeric = typeof value === "number";
|
|
173
173
|
const decimals = DECIMALS[column.id] ?? 0;
|
|
174
174
|
const text = numeric ? `${SIGNED_COLUMNS.has(column.id) && value > 0 ? "+" : ""}${value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals })}` : LABEL_COLUMNS.has(column.id) ? humanLabel(value) : column.id === "title" ? value.trim() : value;
|
|
175
|
-
if (column.id === "share" && numeric && tab === "mix") return { ...shareCell(text, maxShare ? value / maxShare : null, column.width, colors, state.selected
|
|
175
|
+
if (column.id === "share" && numeric && tab === "mix") return { ...shareCell(text, maxShare ? value / maxShare : null, column.width, colors, state.selected), value };
|
|
176
176
|
return { text, value, color: numeric && SIGNED_COLUMNS.has(column.id) ? signedColor(value, colors)
|
|
177
177
|
: column.id === "name" || column.id === "title" ? colors.textBright : column.id === "date" || column.id === "observed" || column.id === "confidence" ? colors.textDim : colors.text };
|
|
178
178
|
}} selectedTextOverridesCellColor showHorizontalScrollbar resetScrollKey={`${kind}:${symbol}:${tab}:${mix}:${country}:${chart}`}
|
|
@@ -4,6 +4,7 @@ import { companyQuery, fetchCompanyData, type CompanyMode } from "./client";
|
|
|
4
4
|
export function companyHeadless(mode: CompanyMode): HeadlessPaneDefinition<"bundle"> {
|
|
5
5
|
return {
|
|
6
6
|
shape: "bundle",
|
|
7
|
+
freshness: { source: "Company filings and calls", status: "not-a-feed", basis: "reported data" },
|
|
7
8
|
argument: { kind: "ticker", description: "Listed company ticker, including exchange-qualified global symbols.", placeholder: "ticker" },
|
|
8
9
|
discovery: { aliases: [mode === "kpis" ? "KPIS" : "GUIDE"], dataRequirements: ["Gloom Cloud company disclosures"],
|
|
9
10
|
limitations: ["Pro dataset with a fixed latest preview on Free", "Coverage follows available company disclosures; missing data is not zero", "Compare matching definition, period, currency, basis and scope", "Fiscal labels without explicit calendar dates are retained without inferred dates"] },
|
|
@@ -104,6 +104,7 @@ export function createCongressHeadless(
|
|
|
104
104
|
): HeadlessPaneDefinition<"rows"> {
|
|
105
105
|
return {
|
|
106
106
|
shape: "rows",
|
|
107
|
+
freshness: { source: "House and Senate disclosures", status: "not-a-feed", basis: "filed reports" },
|
|
107
108
|
argument: {
|
|
108
109
|
kind: "ticker",
|
|
109
110
|
optional: true,
|
|
@@ -8,9 +8,19 @@ export interface CorrelationResult {
|
|
|
8
8
|
|
|
9
9
|
export interface DailyClose {
|
|
10
10
|
dateKey: string;
|
|
11
|
+
/** A closing price, or a map series' value for the day (a transit count). */
|
|
11
12
|
close: number;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* How a series moves between two shared dates. Prices use returns. A map
|
|
17
|
+
* series is a daily count that can be zero (Hormuz logs days with no
|
|
18
|
+
* transits), where a return or log change is undefined, so it uses the
|
|
19
|
+
* change in level. Pearson correlation ignores the unit, so the level change
|
|
20
|
+
* needs no scaling.
|
|
21
|
+
*/
|
|
22
|
+
export type ChangeBasis = "return" | "difference";
|
|
23
|
+
|
|
14
24
|
/** Keep the final valid close for each UTC trading date, in chronological order. */
|
|
15
25
|
export function dailyCloses(points: readonly PricePoint[]): DailyClose[] {
|
|
16
26
|
const byDate = new Map<string, number>();
|
|
@@ -41,11 +51,55 @@ export function alignDailyCloses(left: readonly DailyClose[], right: readonly Da
|
|
|
41
51
|
});
|
|
42
52
|
}
|
|
43
53
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
54
|
+
/** A map series' daily values, oldest first; zero is a value, unlike a zero close. */
|
|
55
|
+
export function dailyValues(points: readonly { date: Date; value: number | null }[]): DailyClose[] {
|
|
56
|
+
const byDate = new Map<string, number>();
|
|
57
|
+
for (const point of [...points].sort((left, right) => left.date.getTime() - right.date.getTime())) {
|
|
58
|
+
if (point.value === null || !Number.isFinite(point.value) || !Number.isFinite(point.date.getTime())) continue;
|
|
59
|
+
byDate.set(point.date.toISOString().slice(0, 10), point.value);
|
|
60
|
+
}
|
|
61
|
+
return [...byDate].map(([dateKey, close]) => ({ dateKey, close }));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface PairedChange {
|
|
65
|
+
dateKey: string;
|
|
66
|
+
left: number;
|
|
67
|
+
right: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function change(previous: number, current: number, basis: ChangeBasis): number {
|
|
71
|
+
return basis === "difference" ? current - previous : previous > 0 ? (current - previous) / previous : Number.NaN;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Each side's move between consecutive shared dates, dropped for both sides when either is undefined. */
|
|
75
|
+
export function pairedChanges(
|
|
76
|
+
aligned: readonly AlignedDailyClose[],
|
|
77
|
+
leftBasis: ChangeBasis = "return",
|
|
78
|
+
rightBasis: ChangeBasis = "return",
|
|
79
|
+
): PairedChange[] {
|
|
80
|
+
const changes: PairedChange[] = [];
|
|
81
|
+
for (let index = 1; index < aligned.length; index++) {
|
|
82
|
+
const previous = aligned[index - 1]!;
|
|
83
|
+
const current = aligned[index]!;
|
|
84
|
+
const left = change(previous.leftClose, current.leftClose, leftBasis);
|
|
85
|
+
const right = change(previous.rightClose, current.rightClose, rightBasis);
|
|
86
|
+
if (Number.isFinite(left) && Number.isFinite(right)) changes.push({ dateKey: current.dateKey, left, right });
|
|
87
|
+
}
|
|
88
|
+
return changes;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function correlateDailyCloses(
|
|
92
|
+
left: readonly DailyClose[],
|
|
93
|
+
right: readonly DailyClose[],
|
|
94
|
+
minObservations = 5,
|
|
95
|
+
leftBasis: ChangeBasis = "return",
|
|
96
|
+
rightBasis: ChangeBasis = "return",
|
|
97
|
+
): CorrelationResult {
|
|
98
|
+
const changes = pairedChanges(alignDailyCloses(left, right), leftBasis, rightBasis);
|
|
99
|
+
return {
|
|
100
|
+
correlation: pearsonCorrelation(changes.map((point) => point.left), changes.map((point) => point.right), minObservations),
|
|
101
|
+
sampleSize: changes.length,
|
|
102
|
+
};
|
|
49
103
|
}
|
|
50
104
|
|
|
51
105
|
function toDateKey(point: PricePoint): string | null {
|
|
@@ -58,17 +112,6 @@ function comparePricePointsByDate(left: PricePoint, right: PricePoint): number {
|
|
|
58
112
|
return getPricePointTimestamp(left) - getPricePointTimestamp(right);
|
|
59
113
|
}
|
|
60
114
|
|
|
61
|
-
export function computeReturns(closes: number[]): number[] {
|
|
62
|
-
const returns: number[] = [];
|
|
63
|
-
for (let i = 1; i < closes.length; i++) {
|
|
64
|
-
const previous = closes[i - 1]!;
|
|
65
|
-
const current = closes[i]!;
|
|
66
|
-
if (!Number.isFinite(previous) || !Number.isFinite(current) || previous === 0) continue;
|
|
67
|
-
returns.push((current - previous) / previous);
|
|
68
|
-
}
|
|
69
|
-
return returns;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
115
|
export function pearsonCorrelation(x: number[], y: number[], minObservations = 5): number | null {
|
|
73
116
|
const n = Math.min(x.length, y.length);
|
|
74
117
|
if (n < minObservations) return null;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map series (`GEO:HORMUZ`) in CORR, read through the same parser and
|
|
3
|
+
* resolver G uses, so an alias G charts is one CORR correlates.
|
|
4
|
+
*/
|
|
5
|
+
import { loadGeoCatalog, type GeoRequest } from "../../../api-client/geo";
|
|
6
|
+
import type { TimeRange } from "../../../time-series/range";
|
|
7
|
+
import { GEO_SERIES_CAPABILITY_ID, parseSeriesExpression } from "../chart-composer/series-expression";
|
|
8
|
+
import { resolveGeoChartSeries } from "../world-venue-map/geo-series";
|
|
9
|
+
import { dailyValues, type DailyClose } from "./compute";
|
|
10
|
+
import { CORRELATION_HISTORY_RESOLUTION } from "./history";
|
|
11
|
+
|
|
12
|
+
/** The map series a CORR entry names, or null for a ticker. */
|
|
13
|
+
export function geoSeriesToken(entry: string): string | null {
|
|
14
|
+
if (!/^GEO:/i.test(entry.trim())) return null;
|
|
15
|
+
const parsed = parseSeriesExpression(entry);
|
|
16
|
+
return parsed?.kind === "capability" && parsed.capabilityId === GEO_SERIES_CAPABILITY_ID ? parsed.seriesId : null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** A map series' daily values over the range. A server without map series says so instead of "not found". */
|
|
20
|
+
export async function loadGeoCorrelationHistory(
|
|
21
|
+
request: GeoRequest,
|
|
22
|
+
seriesId: string,
|
|
23
|
+
range: TimeRange,
|
|
24
|
+
signal?: AbortSignal,
|
|
25
|
+
): Promise<DailyClose[]> {
|
|
26
|
+
try {
|
|
27
|
+
const series = await resolveGeoChartSeries(request, seriesId, { range, resolution: CORRELATION_HISTORY_RESOLUTION }, signal);
|
|
28
|
+
return dailyValues(series.points);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
signal?.throwIfAborted();
|
|
31
|
+
if (!await loadGeoCatalog(request, { signal })) throw new Error("Map series unavailable.");
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -25,7 +25,10 @@ export const paneSchemas = {
|
|
|
25
25
|
discovery: {
|
|
26
26
|
id: "return-correlation",
|
|
27
27
|
aliases: ["correlation", "return correlation", "correlation matrix", "pearson correlation"],
|
|
28
|
-
limitations: [
|
|
28
|
+
limitations: [
|
|
29
|
+
"Correlation is computed from daily returns with at least five shared observations.",
|
|
30
|
+
"GEO:<series> entries correlate a map series' daily change with the others on shared dates.",
|
|
31
|
+
],
|
|
29
32
|
screenshotReadiness: "partial",
|
|
30
33
|
},
|
|
31
34
|
},
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { HeadlessPaneDefinition } from "../../../types/headless";
|
|
2
2
|
import type { TimeRange } from "../../../time-series/range";
|
|
3
|
-
import { formatNumber } from "../../../utils/format";
|
|
3
|
+
import { formatNumber, formatSignificant } from "../../../utils/format";
|
|
4
|
+
import { mixedSessionCloseNote } from "../../../market-data/market/session-close-note";
|
|
4
5
|
import { resolveHeadlessInstrument, loadHeadlessSymbols } from "../shared/headless-market-data";
|
|
5
|
-
import { buildCorrelationMatrix, buildCorrelationSeries, pairKey } from "./matrix/model";
|
|
6
|
+
import { buildCorrelationMatrix, buildCorrelationSeries, buildGeoCorrelationSeries, pairKey, type CorrelationSeries } from "./matrix/model";
|
|
7
|
+
import { geoSeriesToken, loadGeoCorrelationHistory } from "./geo";
|
|
6
8
|
import { buildRelationshipAnalysis, DEFAULT_RELATIONSHIP_SECOND_SYMBOL } from "./relationship/model";
|
|
7
9
|
import { paneSchemas } from "./headless-schema";
|
|
8
|
-
import { CORRELATION_RETURN_BASIS, loadCorrelationHistory } from "./history";
|
|
10
|
+
import { CORRELATION_RETURN_BASIS, GEO_CORRELATION_CHANGE_BASIS, loadCorrelationHistory } from "./history";
|
|
9
11
|
import type { HeadlessPaneContext } from "../../../types/headless";
|
|
12
|
+
import { newestReportTime } from "../../../utils/utc-time";
|
|
13
|
+
import { DAILY_CLOSES } from "../shared/report-freshness";
|
|
10
14
|
|
|
11
15
|
async function loadHistory(ctx: HeadlessPaneContext, key: string, range: TimeRange) {
|
|
12
16
|
const { symbol, exchange } = await resolveHeadlessInstrument(ctx, key);
|
|
@@ -14,9 +18,32 @@ async function loadHistory(ctx: HeadlessPaneContext, key: string, range: TimeRan
|
|
|
14
18
|
ctx.refresh ? { cacheMode: "refresh" } : undefined);
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Daily closes with the exchange the symbol trades on, which the session note
|
|
23
|
+
* needs. A symbol that is not in the local data names no exchange, so its
|
|
24
|
+
* quote says where it lists; a missing quote only leaves the note out.
|
|
25
|
+
*/
|
|
26
|
+
async function loadListedHistory(ctx: HeadlessPaneContext, key: string, range: TimeRange) {
|
|
27
|
+
const { symbol, exchange } = await resolveHeadlessInstrument(ctx, key);
|
|
28
|
+
const [points, quote] = await Promise.all([
|
|
29
|
+
loadHistory(ctx, key, range),
|
|
30
|
+
exchange ? null : (async () => ctx.marketData.getQuote(symbol, "", ctx.refresh ? { cacheMode: "refresh" } : undefined))().catch(() => null),
|
|
31
|
+
]);
|
|
32
|
+
return { exchange: exchange || quote?.listingExchangeName || quote?.exchangeName || "", points };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** A ticker's daily closes, or a map series' daily values read straight from the Cloud client. */
|
|
36
|
+
async function loadCorrelationInput(ctx: HeadlessPaneContext, key: string, range: TimeRange): Promise<CorrelationSeries> {
|
|
37
|
+
const geo = geoSeriesToken(key);
|
|
38
|
+
if (!geo) return buildCorrelationSeries(key, await loadHistory(ctx, key, range));
|
|
39
|
+
const request = <T,>(path: string, init?: RequestInit) => ctx.apiClient.geo<T>(path, { ...init, signal: init?.signal ?? ctx.signal });
|
|
40
|
+
return buildGeoCorrelationSeries(key, await loadGeoCorrelationHistory(request, geo, range, ctx.signal));
|
|
41
|
+
}
|
|
42
|
+
|
|
17
43
|
export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
18
44
|
...paneSchemas["correlation-pane"],
|
|
19
45
|
shape: "rows",
|
|
46
|
+
freshness: DAILY_CLOSES,
|
|
20
47
|
describe: ({ symbols, options }) => `Correlation Matrix | Daily returns | ${options.rangePreset ?? "1Y"} | ${symbols.join(", ")}`,
|
|
21
48
|
columns: [
|
|
22
49
|
{ key: "pair", header: "Pair", format: (_value, row) => `${row.left}/${row.right}` },
|
|
@@ -25,8 +52,8 @@ export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
25
52
|
],
|
|
26
53
|
async load({ symbols, options }, ctx) {
|
|
27
54
|
const range = (options.rangePreset ?? "1Y") as TimeRange;
|
|
28
|
-
const loaded = await loadHeadlessSymbols(symbols, ctx, (symbol) =>
|
|
29
|
-
const bySymbol = new Map(loaded.entries.map(({ symbol, data }) => [symbol,
|
|
55
|
+
const loaded = await loadHeadlessSymbols(symbols, ctx, (symbol) => loadCorrelationInput(ctx, symbol, range));
|
|
56
|
+
const bySymbol = new Map(loaded.entries.map(({ symbol, data }) => [symbol, data]));
|
|
30
57
|
const matrix = buildCorrelationMatrix(symbols, bySymbol);
|
|
31
58
|
const rows = symbols.flatMap((left, index) => symbols.slice(index + 1).map((right) => {
|
|
32
59
|
const result = matrix.results.get(pairKey(left, right));
|
|
@@ -41,6 +68,7 @@ export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
41
68
|
: row.sampleSize < 5 ? "Insufficient shared return observations" : "Zero return variance",
|
|
42
69
|
}));
|
|
43
70
|
return {
|
|
71
|
+
freshness: { asOf: newestReportTime(symbols.map((symbol) => bySymbol.get(symbol)?.prices.at(-1)?.dateKey)) },
|
|
44
72
|
rows, unavailableSymbols,
|
|
45
73
|
errors: [
|
|
46
74
|
...loaded.errors,
|
|
@@ -50,6 +78,7 @@ export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
50
78
|
range,
|
|
51
79
|
unavailablePairs,
|
|
52
80
|
returnAlignment: CORRELATION_RETURN_BASIS,
|
|
81
|
+
...(symbols.some((symbol) => geoSeriesToken(symbol)) ? { mapSeriesChange: GEO_CORRELATION_CHANGE_BASIS } : {}),
|
|
53
82
|
availability: symbols.map((symbol) => ({
|
|
54
83
|
symbol, status: bySymbol.get(symbol)?.status ?? "error", observationCount: bySymbol.get(symbol)?.observationCount ?? 0,
|
|
55
84
|
...(bySymbol.get(symbol)?.integrity ? { integrity: bySymbol.get(symbol)!.integrity } : {}),
|
|
@@ -64,14 +93,18 @@ export const correlationHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
64
93
|
export const relationshipHeadless: HeadlessPaneDefinition<"series"> = {
|
|
65
94
|
...paneSchemas["relationship-graph-pane"],
|
|
66
95
|
shape: "series",
|
|
96
|
+
freshness: DAILY_CLOSES,
|
|
67
97
|
describe: ({ symbols, options }) => `Relationship Graph | ${symbols[0]}/${symbols[1] ?? DEFAULT_RELATIONSHIP_SECOND_SYMBOL} | ${options.range ?? "1Y"}`,
|
|
68
98
|
async load(args, ctx) {
|
|
69
99
|
const symbols = [args.symbols[0]!, args.symbols[1] ?? DEFAULT_RELATIONSHIP_SECOND_SYMBOL];
|
|
70
100
|
const range = (args.options.range ?? "1Y") as TimeRange;
|
|
71
101
|
const correlationWindow = Number(args.options.correlationWindow ?? 120);
|
|
72
|
-
const loaded = await loadHeadlessSymbols(symbols, ctx, (symbol) =>
|
|
73
|
-
const
|
|
102
|
+
const loaded = await loadHeadlessSymbols(symbols, ctx, (symbol) => loadListedHistory(ctx, symbol, range));
|
|
103
|
+
const listings = new Map(loaded.entries.map(({ symbol, data }) => [symbol, data]));
|
|
104
|
+
const histories = new Map(loaded.entries.map(({ symbol, data }) => [symbol, data.points]));
|
|
74
105
|
const analysis = buildRelationshipAnalysis(histories.get(symbols[0]!) ?? [], histories.get(symbols[1]!) ?? [], correlationWindow);
|
|
106
|
+
const [left, right] = symbols.map((symbol) => ({ symbol, ...listings.get(symbol) }));
|
|
107
|
+
const sessionNote = listings.size === 2 ? mixedSessionCloseNote(left!, right!, analysis.aligned.at(-1)?.dateKey) : null;
|
|
75
108
|
const unavailableSymbols = symbols.filter((symbol) => (histories.get(symbol) ?? []).filter((point) => (
|
|
76
109
|
Number.isFinite(point.close) && point.close > 0 && Number.isFinite(new Date(point.date).getTime())
|
|
77
110
|
)).length < 2);
|
|
@@ -86,7 +119,7 @@ export const relationshipHeadless: HeadlessPaneDefinition<"series"> = {
|
|
|
86
119
|
{ id: "correlation", label: `Rolling correlation (${correlationWindow})`, points: analysis.returns.slice(correlationWindow - 1).map(({ date }) => ({ date: date.toISOString(), value: correlations.get(date.getTime()) ?? null })) },
|
|
87
120
|
],
|
|
88
121
|
stats: [
|
|
89
|
-
{ key: "latestRatio", label: "Latest ratio", value: analysis.latestRatio, formatted:
|
|
122
|
+
{ key: "latestRatio", label: "Latest ratio", value: analysis.latestRatio, formatted: formatSignificant(analysis.latestRatio ?? undefined) },
|
|
90
123
|
{ key: "latestCorrelation", label: `Rolling correlation (${correlationWindow})`, value: analysis.latestCorrelation, formatted: formatNumber(analysis.latestCorrelation ?? undefined, 3) },
|
|
91
124
|
...(["beta", "alpha", "rSquared"] as const).map((key) => ({
|
|
92
125
|
key, label: { beta: "Beta", alpha: "Alpha", rSquared: "R squared" }[key],
|
|
@@ -102,6 +135,7 @@ export const relationshipHeadless: HeadlessPaneDefinition<"series"> = {
|
|
|
102
135
|
metadata: {
|
|
103
136
|
left: symbols[0], right: symbols[1], range, correlationWindow,
|
|
104
137
|
returnAlignment: CORRELATION_RETURN_BASIS,
|
|
138
|
+
...(sessionNote ? { notices: [sessionNote] } : {}),
|
|
105
139
|
firstDate: analysis.aligned.at(0)?.dateKey ?? null,
|
|
106
140
|
lastDate: analysis.aligned.at(-1)?.dateKey ?? null,
|
|
107
141
|
...(analysis.integrity ? { integrity: analysis.integrity } : {}),
|
|
@@ -17,3 +17,5 @@ export async function loadCorrelationHistory(
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const CORRELATION_RETURN_BASIS = "Local-price close-to-close returns between shared UTC dates; cash distributions and FX conversion are excluded, and exchange closing times may differ.";
|
|
20
|
+
|
|
21
|
+
export const GEO_CORRELATION_CHANGE_BASIS = "Map series (GEO:) use the change in daily value between the same shared UTC dates, because counts such as transits can be zero.";
|
|
@@ -15,7 +15,10 @@ import { useShortcut } from "../../../react/input";
|
|
|
15
15
|
import { buildChartKey } from "../../../market-data/selectors";
|
|
16
16
|
import { formatTickerListInput } from "../../../tickers/list";
|
|
17
17
|
import { isPlainKey } from "../../../utils/keyboard";
|
|
18
|
-
import {
|
|
18
|
+
import { useAsyncResource } from "../../../react/async-resource";
|
|
19
|
+
import { cloudGeoRequest } from "../world-venue-map/client";
|
|
20
|
+
import { geoSeriesToken, loadGeoCorrelationHistory } from "./geo";
|
|
21
|
+
import { formatCorrelation, type DailyClose } from "./compute";
|
|
19
22
|
import {
|
|
20
23
|
CORRELATION_RANGE_OPTIONS,
|
|
21
24
|
DEFAULT_CORRELATION_SYMBOLS,
|
|
@@ -37,6 +40,7 @@ import {
|
|
|
37
40
|
ROW_HEADER_WIDTH,
|
|
38
41
|
buildCorrelationMatrix,
|
|
39
42
|
buildCorrelationPaneTitle,
|
|
43
|
+
buildGeoCorrelationSeries,
|
|
40
44
|
buildStatusSummary,
|
|
41
45
|
type CorrelationSeries,
|
|
42
46
|
displaySymbol,
|
|
@@ -50,6 +54,13 @@ import { CORRELATION_HISTORY_RESOLUTION } from "./history";
|
|
|
50
54
|
import { buildMatrixPairHistory, clampMatrixCursor, matrixChartRows, matrixSelection, moveMatrixCursor, type MatrixCursor } from "./matrix/selection";
|
|
51
55
|
import { MatrixPairChart } from "./matrix/pair-chart";
|
|
52
56
|
|
|
57
|
+
/** A map series' values and when they arrived; after a failed load, the error and any values kept from before. */
|
|
58
|
+
interface GeoSeriesLoad {
|
|
59
|
+
values?: DailyClose[];
|
|
60
|
+
fetchedAt?: number;
|
|
61
|
+
error?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
53
64
|
function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
|
|
54
65
|
const pane = usePaneInstance();
|
|
55
66
|
const { navigateTicker, pinTicker } = usePluginTickerActions();
|
|
@@ -75,9 +86,12 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
75
86
|
const matrixScrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
76
87
|
const horizontalScrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
77
88
|
|
|
89
|
+
const entries = settings.symbolsError ? [] : settings.symbols;
|
|
90
|
+
const geoEntries = entries.filter((entry) => geoSeriesToken(entry));
|
|
91
|
+
const geoKey = geoEntries.join(",");
|
|
78
92
|
const instruments = useMemo(() => {
|
|
79
93
|
if (settings.symbolsError) return [];
|
|
80
|
-
return settings.symbols.map((symbol) => {
|
|
94
|
+
return settings.symbols.filter((symbol) => !geoSeriesToken(symbol)).map((symbol) => {
|
|
81
95
|
const ticker = tickers.get(symbol);
|
|
82
96
|
return {
|
|
83
97
|
symbol,
|
|
@@ -103,6 +117,28 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
103
117
|
|
|
104
118
|
const chartEntries = useChartQueries(chartRequests);
|
|
105
119
|
|
|
120
|
+
// Map series load beside the tickers; one that fails leaves the others and every ticker pair working.
|
|
121
|
+
// A failed refresh keeps the series' last values for the same range, as a ticker keeps its last history.
|
|
122
|
+
const geoRetainedRef = useRef(new Map<string, { values: DailyClose[]; fetchedAt: number }>());
|
|
123
|
+
const geoLoader = useMemo(() => geoKey ? async () => {
|
|
124
|
+
const range = settings.rangePreset;
|
|
125
|
+
const results = await Promise.allSettled(geoEntries.map((entry) => (
|
|
126
|
+
loadGeoCorrelationHistory(cloudGeoRequest, geoSeriesToken(entry)!, range)
|
|
127
|
+
)));
|
|
128
|
+
return new Map(geoEntries.map((entry, index): [string, GeoSeriesLoad] => {
|
|
129
|
+
const result = results[index]!;
|
|
130
|
+
const key = `${range}|${entry}`;
|
|
131
|
+
if (result.status === "fulfilled") {
|
|
132
|
+
const loaded = { values: result.value, fetchedAt: Date.now() };
|
|
133
|
+
geoRetainedRef.current.set(key, loaded);
|
|
134
|
+
return [entry, loaded];
|
|
135
|
+
}
|
|
136
|
+
const error = result.reason instanceof Error ? result.reason.message : String(result.reason);
|
|
137
|
+
return [entry, { ...geoRetainedRef.current.get(key), error }];
|
|
138
|
+
}));
|
|
139
|
+
} : null, [geoKey, settings.rangePreset]);
|
|
140
|
+
const geoHistory = useAsyncResource(geoLoader, { keepPreviousData: true });
|
|
141
|
+
|
|
106
142
|
const seriesBySymbol = useMemo(() => {
|
|
107
143
|
const map = new Map<string, CorrelationSeries>();
|
|
108
144
|
for (let i = 0; i < instruments.length; i++) {
|
|
@@ -112,10 +148,21 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
112
148
|
const entry = chartEntries.get(key);
|
|
113
149
|
map.set(instrument.symbol, getSeriesForEntry(instrument.symbol, entry, settings.rangePreset));
|
|
114
150
|
}
|
|
151
|
+
for (const symbol of geoEntries) {
|
|
152
|
+
const loaded = geoHistory.data?.get(symbol);
|
|
153
|
+
map.set(symbol, !loaded
|
|
154
|
+
? { symbol, prices: [], basis: "difference", status: "loading", observationCount: 0 }
|
|
155
|
+
: loaded.values
|
|
156
|
+
? {
|
|
157
|
+
...buildGeoCorrelationSeries(symbol, loaded.values),
|
|
158
|
+
loading: geoHistory.loading, refreshError: loaded.error, fetchedAt: loaded.fetchedAt,
|
|
159
|
+
}
|
|
160
|
+
: { symbol, prices: [], basis: "difference", status: "error", observationCount: 0, refreshError: loaded.error });
|
|
161
|
+
}
|
|
115
162
|
return map;
|
|
116
|
-
}, [chartEntries, chartRequests, instruments, settings.rangePreset]);
|
|
163
|
+
}, [chartEntries, chartRequests, instruments, settings.rangePreset, geoKey, geoHistory.data, geoHistory.loading]);
|
|
117
164
|
|
|
118
|
-
const symbols =
|
|
165
|
+
const symbols = entries;
|
|
119
166
|
const symbolsKey = symbols.join(",");
|
|
120
167
|
const cursor = clampMatrixCursor(cellCursor, symbols.length);
|
|
121
168
|
const selection = matrixSelection(symbols, cursor);
|
|
@@ -139,15 +186,20 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
139
186
|
const refresh = useCallback(() => {
|
|
140
187
|
const coordinator = getSharedMarketDataCoordinator();
|
|
141
188
|
for (const request of chartRequests) void coordinator?.loadChart(request, { forceRefresh: true });
|
|
142
|
-
|
|
189
|
+
if (geoKey) void geoHistory.reload();
|
|
190
|
+
}, [chartRequests, geoKey, geoHistory.reload]);
|
|
143
191
|
|
|
144
192
|
const openSymbol = useCallback((symbol: string) => {
|
|
193
|
+
if (geoSeriesToken(symbol)) {
|
|
194
|
+
createPaneFromTemplate("chart-composer-pane", { arg: symbol });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
145
197
|
if (tickers.has(symbol)) {
|
|
146
198
|
pinTicker(symbol, { floating: true, paneType: TICKER_RESEARCH_PANE_ID });
|
|
147
199
|
return;
|
|
148
200
|
}
|
|
149
201
|
navigateTicker(symbol);
|
|
150
|
-
}, [navigateTicker, pinTicker, tickers]);
|
|
202
|
+
}, [createPaneFromTemplate, navigateTicker, pinTicker, tickers]);
|
|
151
203
|
|
|
152
204
|
/** Hovered symbols remain a keyboard starting point; Left reaches their row cursor. */
|
|
153
205
|
const moveCursor = (key: string) => {
|
|
@@ -170,6 +222,8 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
170
222
|
event.preventDefault();
|
|
171
223
|
event.stopPropagation();
|
|
172
224
|
if (hoveredSymbol && symbols.includes(hoveredSymbol)) openSymbol(hoveredSymbol);
|
|
225
|
+
// Ratio and beta are price measures, so a pair with a map series charts both in G instead.
|
|
226
|
+
else if (pair && pair.some((entry) => geoSeriesToken(entry))) createPaneFromTemplate("chart-composer-pane", { arg: formatTickerListInput(pair) });
|
|
173
227
|
else if (pair) createPaneFromTemplate("relationship-graph-pane", { symbols: pair, arg: formatTickerListInput(pair) });
|
|
174
228
|
else openSymbol(selection[0]);
|
|
175
229
|
}
|
|
@@ -210,13 +264,13 @@ function CorrelationMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
210
264
|
}, []);
|
|
211
265
|
|
|
212
266
|
const headerBg = colors.panel;
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
);
|
|
267
|
+
const labelWidth = Math.max(0, ...symbols.map((symbol) => displaySymbol(symbol).length));
|
|
268
|
+
const rowHeaderWidth = Math.max(ROW_HEADER_WIDTH, Math.min(12, labelWidth + 2));
|
|
269
|
+
// A map series label (SUEZ.TANKER) is wider than a ticker's: columns keep room for it and the matrix scrolls instead.
|
|
270
|
+
const minCellWidth = Math.max(MIN_MATRIX_CELL_WIDTH, labelWidth + 2);
|
|
217
271
|
const cellCount = Math.max(1, symbols.length);
|
|
218
|
-
const availableCellWidth = Math.floor((Math.max(width - rowHeaderWidth - 4, cellCount *
|
|
219
|
-
const cellWidth = Math.max(
|
|
272
|
+
const availableCellWidth = Math.floor((Math.max(width - rowHeaderWidth - 4, cellCount * minCellWidth)) / cellCount);
|
|
273
|
+
const cellWidth = Math.max(minCellWidth, Math.min(MATRIX_CELL_WIDTH, availableCellWidth));
|
|
220
274
|
// Rows are exactly as wide as the matrix (after the one-cell inset), so the
|
|
221
275
|
// zebra and hover bands stop at the last column instead of running on.
|
|
222
276
|
const matrixRowWidth = 1 + rowHeaderWidth + symbols.length * cellWidth;
|
|
@@ -401,9 +455,9 @@ export const correlationModule: PluginModule = {
|
|
|
401
455
|
headless: correlationHeadless,
|
|
402
456
|
paneId: "correlation",
|
|
403
457
|
label: "Correlation Matrix",
|
|
404
|
-
description: "Date-aligned Pearson correlation matrix for ticker returns.",
|
|
458
|
+
description: "Date-aligned Pearson correlation matrix for ticker returns and map series such as GEO:HORMUZ.",
|
|
405
459
|
keywords: ["correlation", "corr", "matrix", "pearson", "returns", "covariance"],
|
|
406
|
-
shortcut: { prefix: "CORR", argPlaceholder: "tickers", argKind: "ticker-list" },
|
|
460
|
+
shortcut: { prefix: "CORR", argPlaceholder: "tickers", argKind: "ticker-list", keepArgToken: (token) => !!geoSeriesToken(token) },
|
|
407
461
|
wizard: [
|
|
408
462
|
{
|
|
409
463
|
key: "tickers",
|