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,146 @@
|
|
|
1
|
+
import type { MarketHeatmapAsset } from "../../../api-client/market-discovery";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The board's grouping and move arithmetic, shared by the pane and the `fn HM`
|
|
5
|
+
* report so a sector reads the same in both. Isomorphic: no React or renderer.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
type HeatmapMoveAsset = Pick<MarketHeatmapAsset, "symbol" | "hasChange" | "changePercent" | "size" | "sector" | "industry"> & {
|
|
9
|
+
/** Treemap area, when it is not `size` itself. */
|
|
10
|
+
weight?: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The move, or null when there is none: no change data is not a flat session.
|
|
15
|
+
* A name without the last session's close still has the move of the open
|
|
16
|
+
* pre-market or after-hours session it streams (`extendedSession`).
|
|
17
|
+
*/
|
|
18
|
+
export function heatmapMove(asset: Pick<MarketHeatmapAsset, "hasChange" | "changePercent"> & { extendedSession?: string }): number | null {
|
|
19
|
+
return (asset.hasChange || asset.extendedSession != null) && typeof asset.changePercent === "number" && Number.isFinite(asset.changePercent)
|
|
20
|
+
? asset.changePercent
|
|
21
|
+
: null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type HeatmapGrouping = "sector-industry" | "sector" | "flat";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Sector and industry blocks when the board knows its sectors. A board where
|
|
28
|
+
* most of the value has none (ETFs, or a snapshot whose classification
|
|
29
|
+
* failed) lays out flat rather than as one big unlabeled block.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveHeatmapGrouping(assets: readonly HeatmapMoveAsset[], industries: boolean): HeatmapGrouping {
|
|
32
|
+
let total = 0;
|
|
33
|
+
let classified = 0;
|
|
34
|
+
const sectors = new Set<string>();
|
|
35
|
+
for (const asset of assets) {
|
|
36
|
+
const weight = asset.weight ?? asset.size ?? 0;
|
|
37
|
+
total += weight;
|
|
38
|
+
if (asset.sector) {
|
|
39
|
+
classified += weight;
|
|
40
|
+
sectors.add(asset.sector);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (sectors.size < 2 || classified < total / 2) return "flat";
|
|
44
|
+
return industries ? "sector-industry" : "sector";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The move of a set of names weighted by their size (market cap, an ETF's net
|
|
49
|
+
* assets, a position's value), over the names that have both. Null when none do.
|
|
50
|
+
*/
|
|
51
|
+
export function sizeWeightedMove(assets: readonly HeatmapMoveAsset[]): number | null {
|
|
52
|
+
let weight = 0;
|
|
53
|
+
let weightedMove = 0;
|
|
54
|
+
for (const asset of assets) {
|
|
55
|
+
const change = heatmapMove(asset);
|
|
56
|
+
const size = asset.size ?? 0;
|
|
57
|
+
if (change == null || !(size > 0)) continue;
|
|
58
|
+
weight += size;
|
|
59
|
+
weightedMove += change * size;
|
|
60
|
+
}
|
|
61
|
+
return weight > 0 ? weightedMove / weight : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type HeatmapGroupBy = "sector" | "industry";
|
|
65
|
+
|
|
66
|
+
export interface HeatmapGroupSummary {
|
|
67
|
+
/** The sector or industry; null for names the snapshot does not classify, or every name on a flat board. */
|
|
68
|
+
group: string | null;
|
|
69
|
+
/** The industry's sector, when grouping by industry. */
|
|
70
|
+
sector: string | null;
|
|
71
|
+
names: number;
|
|
72
|
+
/** Total size: market cap, or net assets on the ETF board. */
|
|
73
|
+
size: number;
|
|
74
|
+
/** This group's share of the board's total size. */
|
|
75
|
+
share: number;
|
|
76
|
+
move: number | null;
|
|
77
|
+
/** Names with a move, and the size they carry; the rest have no change data yet. */
|
|
78
|
+
moved: number;
|
|
79
|
+
up: number;
|
|
80
|
+
down: number;
|
|
81
|
+
unchanged: number;
|
|
82
|
+
best: { symbol: string; move: number } | null;
|
|
83
|
+
worst: { symbol: string; move: number } | null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function summarize(group: string | null, sector: string | null, assets: readonly HeatmapMoveAsset[], boardSize: number): HeatmapGroupSummary {
|
|
87
|
+
let up = 0;
|
|
88
|
+
let down = 0;
|
|
89
|
+
let unchanged = 0;
|
|
90
|
+
let size = 0;
|
|
91
|
+
let best: HeatmapGroupSummary["best"] = null;
|
|
92
|
+
let worst: HeatmapGroupSummary["worst"] = null;
|
|
93
|
+
for (const asset of assets) {
|
|
94
|
+
size += asset.size ?? 0;
|
|
95
|
+
const move = heatmapMove(asset);
|
|
96
|
+
if (move == null) continue;
|
|
97
|
+
if (move > 0) up += 1;
|
|
98
|
+
else if (move < 0) down += 1;
|
|
99
|
+
else unchanged += 1;
|
|
100
|
+
if (!best || move > best.move) best = { symbol: asset.symbol, move };
|
|
101
|
+
if (!worst || move < worst.move) worst = { symbol: asset.symbol, move };
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
group,
|
|
105
|
+
sector,
|
|
106
|
+
names: assets.length,
|
|
107
|
+
size,
|
|
108
|
+
share: boardSize > 0 ? size / boardSize : 0,
|
|
109
|
+
move: sizeWeightedMove(assets),
|
|
110
|
+
moved: up + down + unchanged,
|
|
111
|
+
up,
|
|
112
|
+
down,
|
|
113
|
+
unchanged,
|
|
114
|
+
best,
|
|
115
|
+
worst,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* One summary per sector or industry, largest first as the board lays them
|
|
121
|
+
* out. A flat board (ETFs) is one group of every name. Unclassified names form
|
|
122
|
+
* their own group last.
|
|
123
|
+
*/
|
|
124
|
+
export function summarizeHeatmapGroups(
|
|
125
|
+
assets: readonly HeatmapMoveAsset[],
|
|
126
|
+
groupBy: HeatmapGroupBy,
|
|
127
|
+
): { grouping: HeatmapGrouping; groups: HeatmapGroupSummary[]; board: HeatmapGroupSummary } {
|
|
128
|
+
const grouping = resolveHeatmapGrouping(assets, groupBy === "industry");
|
|
129
|
+
const boardSize = assets.reduce((sum, asset) => sum + (asset.size ?? 0), 0);
|
|
130
|
+
const board = summarize(null, null, assets, boardSize);
|
|
131
|
+
if (grouping === "flat") return { grouping, groups: [board], board };
|
|
132
|
+
const buckets = new Map<string, { group: string | null; sector: string | null; assets: HeatmapMoveAsset[] }>();
|
|
133
|
+
for (const asset of assets) {
|
|
134
|
+
const sector = asset.sector ?? null;
|
|
135
|
+
const group = sector == null ? null : grouping === "sector-industry" ? asset.industry ?? null : sector;
|
|
136
|
+
const key = `${sector ?? ""}\u0000${group ?? ""}`;
|
|
137
|
+
const bucket = buckets.get(key) ?? { group, sector, assets: [] };
|
|
138
|
+
bucket.assets.push(asset);
|
|
139
|
+
buckets.set(key, bucket);
|
|
140
|
+
}
|
|
141
|
+
const groups = [...buckets.values()]
|
|
142
|
+
.map((bucket) => summarize(bucket.group, grouping === "sector-industry" ? bucket.sector : null, bucket.assets, boardSize))
|
|
143
|
+
.sort((left, right) => Number(left.sector == null && left.group == null) - Number(right.sector == null && right.group == null)
|
|
144
|
+
|| right.size - left.size);
|
|
145
|
+
return { grouping, groups, board };
|
|
146
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { MarketHeatmapAsset, MarketHeatmapUniverseId } from "../../../api-c
|
|
|
3
3
|
import { useAppSelector, usePaneStateValue } from "../../../state/app/context";
|
|
4
4
|
import type { ColumnConfig } from "../../../types/config";
|
|
5
5
|
import type { TickerFinancials } from "../../../types/financials";
|
|
6
|
+
import { getSessionMoveDisplay, type ExtendedSession } from "../../../market-data/market/status";
|
|
6
7
|
import type { TickerRecord } from "../../../types/ticker";
|
|
7
8
|
import { getSortValue, type ColumnContext } from "../portfolio-list/metrics";
|
|
8
9
|
|
|
@@ -36,6 +37,8 @@ export interface HeatmapBoardAsset extends MarketHeatmapAsset {
|
|
|
36
37
|
sizeCurrency?: string;
|
|
37
38
|
/** Treemap area, when it is not `size` itself. */
|
|
38
39
|
weight?: number;
|
|
40
|
+
/** The price and move are this open pre-market or after-hours session's, from the regular close. */
|
|
41
|
+
extendedSession?: ExtendedSession;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
export interface HeatmapPortfolioPane {
|
|
@@ -48,6 +51,19 @@ export function heatmapTabId(value: string | null | undefined): HeatmapTabId {
|
|
|
48
51
|
return "us-equity";
|
|
49
52
|
}
|
|
50
53
|
|
|
54
|
+
/** Pane state where the pane says which kind of list its portfolio tab shows, for the header to read. */
|
|
55
|
+
export const HEATMAP_COLLECTION_KIND_STATE_KEY = "collectionKind";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Whether Size by changes the board: the market boards and a watchlist, never
|
|
59
|
+
* a portfolio, whose holdings are always sized by position value. Until the
|
|
60
|
+
* pane has said which list its tab shows, the control stays away.
|
|
61
|
+
*/
|
|
62
|
+
export function heatmapSizeByApplies(universe: unknown, collectionKind: unknown): boolean {
|
|
63
|
+
return heatmapTabId(typeof universe === "string" ? universe : null) !== PORTFOLIO_HEATMAP_TAB
|
|
64
|
+
|| collectionKind === "watchlist";
|
|
65
|
+
}
|
|
66
|
+
|
|
51
67
|
export function isRemoteHeatmapUniverse(value: HeatmapTabId): value is MarketHeatmapUniverseId {
|
|
52
68
|
return value !== PORTFOLIO_HEATMAP_TAB;
|
|
53
69
|
}
|
|
@@ -200,16 +216,19 @@ export function buildPortfolioHeatmapAssets({
|
|
|
200
216
|
const symbol = ticker.metadata.ticker;
|
|
201
217
|
const snapshot = financials.get(symbol);
|
|
202
218
|
const quote = snapshot?.quote;
|
|
203
|
-
|
|
219
|
+
// Colored like the market boards: an open extended session's move, else the regular session's.
|
|
220
|
+
const display = getSessionMoveDisplay(quote);
|
|
221
|
+
const price = display != null && Number.isFinite(display.price) ? display.price : null;
|
|
204
222
|
const size = positiveNumber(getSortValue(sizeColumn, ticker, snapshot, context));
|
|
205
|
-
const hasChange =
|
|
223
|
+
const hasChange = display?.changePercent != null && Number.isFinite(display.changePercent);
|
|
206
224
|
return {
|
|
207
225
|
symbol,
|
|
208
226
|
name: quote?.name?.trim() || ticker.metadata.name || symbol,
|
|
209
227
|
price: price ?? 0,
|
|
210
|
-
change:
|
|
211
|
-
changePercent: hasChange ?
|
|
228
|
+
change: display?.change != null && Number.isFinite(display.change) ? display.change : 0,
|
|
229
|
+
changePercent: hasChange ? display.changePercent! : 0,
|
|
212
230
|
hasChange,
|
|
231
|
+
...(display?.session ? { extendedSession: display.session } : {}),
|
|
213
232
|
size,
|
|
214
233
|
weight: size == null ? undefined : kind === "portfolio" ? size : heatmapSizeWeight(size, sizeBy),
|
|
215
234
|
sizeKind: "market-cap",
|
|
@@ -81,6 +81,8 @@ export function createMarketMoversHeadless(
|
|
|
81
81
|
): HeadlessPaneDefinition<"rows"> {
|
|
82
82
|
return {
|
|
83
83
|
shape: "rows",
|
|
84
|
+
// A screener snapshot, not a real-time feed; rows keep the time of their own last price.
|
|
85
|
+
freshness: { status: "delayed" },
|
|
84
86
|
argument: { kind: "none" },
|
|
85
87
|
options: [{
|
|
86
88
|
key: "list",
|
|
@@ -120,6 +120,8 @@ function projectValuationHeadlessBundle(
|
|
|
120
120
|
|
|
121
121
|
export const marketValuationHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
122
122
|
shape: "bundle",
|
|
123
|
+
// Each indicator row checks its own release schedule and says when it is stale.
|
|
124
|
+
freshness: { status: "not-a-feed", basis: "published statistics" },
|
|
123
125
|
argument: {
|
|
124
126
|
kind: "free-text",
|
|
125
127
|
placeholder: "indicator",
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { apiClient } from "../../../api-client";
|
|
2
|
+
import { ApiRequestError } from "../../../api-client/errors";
|
|
2
3
|
import type { FundMembersPayload, FundChangesPayload, MemberFundsPayload } from "../../../api-client/members";
|
|
3
4
|
import { createPluginCache } from "../../../data/plugin-cache";
|
|
4
5
|
import { cachedCloudResource, loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
|
|
6
|
+
import { coveredFund, notCoveredMessage } from "./model";
|
|
5
7
|
const policy = { staleMs: 60_000, expireMs: 2 * 60 * 60_000 };
|
|
6
8
|
export const fundListCache = createPluginCache<MemberFundsPayload>({ kind: "member-funds", source: "gloom-cloud", schemaVersion: 1, policy });
|
|
7
9
|
export const fundMembersCache = createPluginCache<FundMembersPayload>({ kind: "fund-members", source: "gloom-cloud", schemaVersion: 1, policy });
|
|
@@ -22,12 +24,27 @@ function validateFunds(data: MemberFundsPayload) {
|
|
|
22
24
|
if (!data || !Array.isArray(data.funds) || !data.funds.every((fund) => typeof fund.ticker === "string" && typeof fund.name === "string")) throw new Error("Unreadable covered funds response");
|
|
23
25
|
return data;
|
|
24
26
|
}
|
|
27
|
+
const UNAVAILABLE = "Fund members are not available on this server yet.";
|
|
25
28
|
async function fetchPayload<T>(fetcher: () => Promise<T>, validate: (data: T) => T) {
|
|
26
|
-
try { return validate(await fetcher()); } catch (error) { throw unavailableOnServer(error,
|
|
29
|
+
try { return validate(await fetcher()); } catch (error) { throw unavailableOnServer(error, UNAVAILABLE); }
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A 404 for one fund means either an uncovered fund or a server without the route, and the two read the
|
|
33
|
+
* same. The covered list tells them apart: a fund missing from a readable list is not covered; a list
|
|
34
|
+
* that cannot be read, or that holds the fund, leaves the server-side message.
|
|
35
|
+
*/
|
|
36
|
+
async function fetchFundPayload<T>(fund: string, fetcher: () => Promise<T>, validate: (data: T) => T, client: Client) {
|
|
37
|
+
try { return validate(await fetcher()); } catch (error) {
|
|
38
|
+
if (error instanceof ApiRequestError && error.status === 404) {
|
|
39
|
+
const funds = await fetchFunds(client).then((payload) => payload.funds, () => []);
|
|
40
|
+
if (funds.length && !coveredFund(funds, fund)) throw new Error(notCoveredMessage(fund, funds));
|
|
41
|
+
}
|
|
42
|
+
throw unavailableOnServer(error, UNAVAILABLE);
|
|
43
|
+
}
|
|
27
44
|
}
|
|
28
45
|
export const fetchFunds = (client: Client = apiClient) => fetchPayload(() => client.getMemberFunds(), validateFunds);
|
|
29
|
-
export const fetchMembers = (fund: string, client: Client = apiClient) =>
|
|
30
|
-
export const fetchChanges = (fund: string, client: Client = apiClient) =>
|
|
46
|
+
export const fetchMembers = (fund: string, client: Client = apiClient) => fetchFundPayload(fund, () => client.getFundMembers(fund), validateMembers, client);
|
|
47
|
+
export const fetchChanges = (fund: string, client: Client = apiClient) => fetchFundPayload(fund, () => client.getFundChanges(fund), validateChanges, client);
|
|
31
48
|
export const cachedFunds = () => cachedCloudResource(fundListCache, "list", validateFunds);
|
|
32
49
|
export const loadFunds = (force = false) => loadCloudResource(fundListCache, "list", () => fetchFunds(), { force, validate: validateFunds });
|
|
33
50
|
export const cachedMembers = (fund: string) => cachedCloudResource(fundMembersCache, fund, validateMembers);
|
|
@@ -15,17 +15,19 @@ export const membersHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
15
15
|
describe: (args) => args.rawArgument ? `MEMB ${args.rawArgument}` : "Index and ETF members",
|
|
16
16
|
async load(args, context) {
|
|
17
17
|
const input = args.symbols[0] ?? args.rawArgument ?? "";
|
|
18
|
-
if (!input) return { rows: (await fetchFunds(context.apiClient)).funds.map((fund) => ({ ...fund })), columns: [{ key: "ticker", header: "Fund" }, { key: "name", header: "Index" }, { key: "asOf", header: "Holdings as of" }] };
|
|
18
|
+
if (!input) return { freshness: { status: "not-a-feed", basis: "fund holdings files" }, rows: (await fetchFunds(context.apiClient)).funds.map((fund) => ({ ...fund })), columns: [{ key: "ticker", header: "Fund" }, { key: "name", header: "Index" }, { key: "asOf", header: "Holdings as of" }] };
|
|
19
19
|
const fund = canonicalFund(input);
|
|
20
20
|
if (args.options.tab === "changes") {
|
|
21
21
|
const data = await fetchChanges(fund, context.apiClient);
|
|
22
|
-
return { rows: data.changes.map((row) => ({ ...row, reason: changeReason(row) })), columns: [{ key: "effectiveDate", header: "Effective" }, { key: "added", header: "Added" }, { key: "removed", header: "Removed" }, { key: "daysToGo", header: "In days", align: "right" }, { key: "reason", header: "Reason" }],
|
|
22
|
+
return { freshness: { status: "not-a-feed", basis: "index changes" }, rows: data.changes.map((row) => ({ ...row, reason: changeReason(row) })), columns: [{ key: "effectiveDate", header: "Effective" }, { key: "added", header: "Added" }, { key: "removed", header: "Removed" }, { key: "daysToGo", header: "In days", align: "right" }, { key: "reason", header: "Reason" }],
|
|
23
23
|
complete: data.available && !data.stale, metadata: { ...data, changes: undefined } };
|
|
24
24
|
}
|
|
25
25
|
const data = await fetchMembers(fund, context.apiClient);
|
|
26
26
|
const movers = args.options.tab === "movers";
|
|
27
27
|
const rows = memberRows(data.members, movers ? "movers" : "members", "", DEFAULT_SORT).flatMap((row) => row.kind === "item" ? [{ ...row.item }] : []);
|
|
28
|
-
|
|
28
|
+
// Member prices are the pane's 15-minute delayed quotes. As in the pane, the fund's snapshot says
|
|
29
|
+
// whether it is stale; the members' own flags are not what the pane reads.
|
|
30
|
+
return { freshness: { status: data.stale ? "stale" : "delayed", delayMinutes: 15, ignoreStaleFlags: true }, rows, columns: movers ? [...columns.slice(0, 3), { key: "contribution", header: "Contrib. pp", align: "right", format: (value) => percent(value as number | null, "", 3) }] : columns,
|
|
29
31
|
complete: !data.stale && data.aggregate.fresh1D === data.aggregate.total,
|
|
30
32
|
unavailableSymbols: data.members.flatMap((row) => row.symbol && row.changePercent === null ? [row.symbol] : []),
|
|
31
33
|
metadata: { fund: data.fund, asOf: data.asOf, snapshotAsOf: data.snapshotAsOf, aggregate: data.aggregate, stale: data.stale } };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FundChange, FundMember } from "../../../api-client/members";
|
|
1
|
+
import type { FundChange, FundMember, MemberFundsPayload } from "../../../api-client/members";
|
|
2
2
|
import type { DataTableColumn } from "../../../components";
|
|
3
3
|
import { buildSectionedRows, type SectionedRow } from "../../../components/data-table/sections";
|
|
4
4
|
import { getTableWidth } from "../../../components/ui/table-layout";
|
|
@@ -6,8 +6,16 @@ import { compareSortValues, type SortPreference } from "../../../utils/sort-valu
|
|
|
6
6
|
export type MembersTab = "members" | "movers" | "changes";
|
|
7
7
|
export const TABS = [{ value: "members", label: "Members" }, { value: "movers", label: "Movers" }, { value: "changes", label: "Changes" }];
|
|
8
8
|
export const isTab = (value: unknown): value is MembersTab => TABS.some((tab) => tab.value === value);
|
|
9
|
-
|
|
9
|
+
const COVERED = [{ ticker: "IVV", name: "S&P 500" }, { ticker: "IJH", name: "S&P 400" }, { ticker: "IJR", name: "S&P 600" }, { ticker: "IWM", name: "Russell 2000" }, { ticker: "IWB", name: "Russell 1000" }];
|
|
10
10
|
export function canonicalFund(input: string) { const symbol = input.split(":")[0]!.trim().toUpperCase(); return ["SPX", "SPY", "^GSPC"].includes(symbol) ? "IVV" : symbol; }
|
|
11
|
+
/** The covered fund the user asked for, by ticker or by an alias such as SPX, or undefined when it is not covered. */
|
|
12
|
+
export function coveredFund(funds: MemberFundsPayload["funds"], input: string) {
|
|
13
|
+
const symbol = canonicalFund(input);
|
|
14
|
+
return funds.find((fund) => fund.ticker === symbol || fund.aliases.some((alias) => alias.toUpperCase() === symbol));
|
|
15
|
+
}
|
|
16
|
+
export function notCoveredMessage(input: string, funds: MemberFundsPayload["funds"]) {
|
|
17
|
+
return `${input.split(":")[0]!.trim().toUpperCase()} is not a covered fund. Covered: ${funds.map((fund) => fund.ticker).join(", ")}.`;
|
|
18
|
+
}
|
|
11
19
|
export function membersTitle(input: string) {
|
|
12
20
|
const requested = input.split(":")[0]!.trim().toUpperCase();
|
|
13
21
|
const fund = canonicalFund(requested);
|
|
@@ -12,7 +12,7 @@ import { Box, type ScrollBoxRenderable } from "../../../ui";
|
|
|
12
12
|
import { nextHeaderSort, type SortPreference } from "../../../utils/sort-values";
|
|
13
13
|
import { isPlainArrowUp, stopSearchFocusNavigation } from "../../../utils/search-focus-navigation";
|
|
14
14
|
import { cachedChanges, cachedFunds, cachedMembers, loadChanges, loadFunds, loadMembers } from "./client";
|
|
15
|
-
import { canonicalFund, changeColumns, changeLabel, changeReason,
|
|
15
|
+
import { canonicalFund, changeColumns, changeLabel, changeReason, coveredFund, decimal, DEFAULT_SORT, isTab, memberColumns, memberRows, membersTitle, notCoveredMessage, percent, TABS, type MembersTab } from "./model";
|
|
16
16
|
|
|
17
17
|
type ViewProps = Pick<PaneProps, "width" | "height" | "focused"> & { fund: string; active: boolean };
|
|
18
18
|
const rowKey = (row: SectionedRow<FundMember>) => row.key;
|
|
@@ -156,13 +156,20 @@ function FundPicker({ width, height, focused, choose }: Pick<PaneProps, "width"
|
|
|
156
156
|
onActivate={(row) => choose(row.ticker)} sortColumnId={null} sortDirection="asc" renderCell={(row, col) => ({ text: String(row[col.id as "ticker"] ?? "--") })} />}
|
|
157
157
|
</PaneStatusBody>;
|
|
158
158
|
}
|
|
159
|
+
type FundPaneProps = Pick<PaneProps, "width" | "height" | "focused"> & { fund: string; requested: string };
|
|
160
|
+
/** The covered list is the server's, so a fund it adds opens without an app update. A list that cannot be read leaves the fund's own load to report the failure. */
|
|
161
|
+
function CoveredFund({ fund, requested, ...props }: FundPaneProps) {
|
|
162
|
+
const resource = useAsyncResource(loadFunds, { initialData: cachedFunds });
|
|
163
|
+
const funds = resource.data?.payload.funds;
|
|
164
|
+
if (funds?.length && !coveredFund(funds, fund)) return <PaneStatusBody empty emptyTitle={notCoveredMessage(requested, funds)} />;
|
|
165
|
+
return <FundView key={fund} fund={fund} {...props} />;
|
|
166
|
+
}
|
|
159
167
|
export function MembersPane(props: PaneProps) {
|
|
160
168
|
const { symbol } = usePaneTickerIdentity();
|
|
161
169
|
const [chosen, choose] = usePluginPaneState("fund", "");
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
usePaneTitle(membersTitle(
|
|
170
|
+
const requested = symbol ?? chosen;
|
|
171
|
+
const fund = canonicalFund(requested);
|
|
172
|
+
usePaneTitle(membersTitle(requested));
|
|
165
173
|
if (!fund) return <FundPicker {...props} choose={choose} />;
|
|
166
|
-
|
|
167
|
-
return <FundView key={fund} fund={fund} {...props} />;
|
|
174
|
+
return <CoveredFund fund={fund} requested={requested} {...props} />;
|
|
168
175
|
}
|
|
@@ -140,6 +140,7 @@ const text = (value: unknown) => (typeof value === "string" ? value : "");
|
|
|
140
140
|
|
|
141
141
|
export const distressHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
142
142
|
shape: "rows",
|
|
143
|
+
freshness: { source: "Public filings and insolvency notices", status: "not-a-feed", basis: "filed records" },
|
|
143
144
|
description: "Dated public records about companies in difficulty: US 8-K bankruptcy, obligation and listing filings, SEC going-concern disclosures, Taiwan exchange listing designations, and French and UK company insolvency notices. No scores or predictions.",
|
|
144
145
|
argument: { kind: "none" },
|
|
145
146
|
discovery: {
|
|
@@ -6,6 +6,7 @@ export const moneyMarketsHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
6
6
|
discovery: { aliases: ["BTMM"], dataRequirements: ["Gloom Cloud money-markets endpoint"],
|
|
7
7
|
limitations: ["Published daily and weekly observations", "Treasury bill discount yields", "Net liquidity is a same-date proxy"] },
|
|
8
8
|
shape: "bundle", argument: { kind: "none" },
|
|
9
|
+
freshness: { source: "FRED", status: "not-a-feed", basis: "published daily and weekly data" },
|
|
9
10
|
options: [{ key: "tab", type: "enum", description: "Money-market view.", values: [{ value: "rates" }, { value: "bills" }, { value: "liquidity" }], defaultValue: "rates" }],
|
|
10
11
|
describe: "US money markets",
|
|
11
12
|
async load(args, ctx) {
|
|
@@ -81,6 +81,8 @@ function projectNewsHeadless(
|
|
|
81
81
|
return {
|
|
82
82
|
asOf: now.toISOString(),
|
|
83
83
|
items,
|
|
84
|
+
// Published stories, dated by the newest; the list is a history, so its last story is not stale data.
|
|
85
|
+
freshness: { status: "not-a-feed", basis: "published stories", observedKey: "publishedAt", oldest: null },
|
|
84
86
|
metadata: {
|
|
85
87
|
nextCursor: response.nextCursor,
|
|
86
88
|
sentiment,
|
|
@@ -25,6 +25,7 @@ import { NEWS_INDUSTRY_CODES, NEWS_QUERY_PRESETS, parseNewsIndustryCode } from "
|
|
|
25
25
|
import { createRssNewsCapability } from "./rss/source";
|
|
26
26
|
import { rssCliCommand } from "./rss/cli";
|
|
27
27
|
import { newsFeedHeadless } from "../headless";
|
|
28
|
+
import type { PaneDef } from "../../../../types/plugin";
|
|
28
29
|
|
|
29
30
|
const TopPane = createNewsPresetPane({
|
|
30
31
|
paneKey: "top:curated",
|
|
@@ -61,8 +62,11 @@ export const BreakingPane = createNewsPresetPane({
|
|
|
61
62
|
|
|
62
63
|
let disposeBreakingNewsNotifications: (() => void) | null = null;
|
|
63
64
|
|
|
65
|
+
// A rendered news pane is a list of published stories, dated by its newest.
|
|
66
|
+
const NEWS_REPORT_FRESHNESS: PaneDef["reportFreshness"] = { status: "not-a-feed", basis: "published stories" };
|
|
67
|
+
|
|
64
68
|
const newsWirePanes: PluginModule["panes"] = [
|
|
65
|
-
{ id: "news-top", name: "Top News", icon: "T", component: TopPane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 90, height: 30 } },
|
|
69
|
+
{ id: "news-top", reportFreshness: NEWS_REPORT_FRESHNESS, name: "Top News", icon: "T", component: TopPane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 90, height: 30 } },
|
|
66
70
|
{
|
|
67
71
|
id: "news-feed",
|
|
68
72
|
name: "News Feed",
|
|
@@ -75,6 +79,7 @@ const newsWirePanes: PluginModule["panes"] = [
|
|
|
75
79
|
},
|
|
76
80
|
{
|
|
77
81
|
id: "news-industry",
|
|
82
|
+
reportFreshness: NEWS_REPORT_FRESHNESS,
|
|
78
83
|
name: TOPIC_NEWS_TITLE,
|
|
79
84
|
icon: "S",
|
|
80
85
|
component: IndustryPane,
|
|
@@ -85,6 +90,7 @@ const newsWirePanes: PluginModule["panes"] = [
|
|
|
85
90
|
},
|
|
86
91
|
{
|
|
87
92
|
id: NEWS_STORY_PANE_ID,
|
|
93
|
+
reportFreshness: NEWS_REPORT_FRESHNESS,
|
|
88
94
|
name: "Story",
|
|
89
95
|
icon: "A",
|
|
90
96
|
component: NewsStoryPane,
|
|
@@ -94,6 +100,7 @@ const newsWirePanes: PluginModule["panes"] = [
|
|
|
94
100
|
},
|
|
95
101
|
{
|
|
96
102
|
id: "news-breaking",
|
|
103
|
+
reportFreshness: NEWS_REPORT_FRESHNESS,
|
|
97
104
|
name: "Breaking News",
|
|
98
105
|
icon: "!",
|
|
99
106
|
component: BreakingPane,
|
|
@@ -2,7 +2,8 @@ import { apiClient } from "../../../api-client";
|
|
|
2
2
|
import { withCliServices, withConfigData } from "../../../cli/scoped-context";
|
|
3
3
|
import { CLI_COMMAND_GROUPS } from "../../../cli/help";
|
|
4
4
|
import { dryRunNote } from "../../../cli/helpers";
|
|
5
|
-
import { requireArg } from "../../../cli/commands/command-utils";
|
|
5
|
+
import { requireArg, takeOption } from "../../../cli/commands/command-utils";
|
|
6
|
+
import { EXCHANGE_OPTION, requireListingArg } from "../../../cli/listing-arg";
|
|
6
7
|
import { createPluginPersistence } from "../../plugin-persistence";
|
|
7
8
|
import type { CliCommandDef } from "../../../types/plugin";
|
|
8
9
|
import { cliStyles } from "../../../utils/cli-output";
|
|
@@ -17,9 +18,16 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
17
18
|
help: {
|
|
18
19
|
group: CLI_COMMAND_GROUPS.portfolios,
|
|
19
20
|
usage: ["notes show <symbol>", "notes set <symbol> <text...>", "notes delete <symbol>", "notes quick list", "notes export [dir]"],
|
|
20
|
-
|
|
21
|
+
options: [EXCHANGE_OPTION],
|
|
22
|
+
examples: ["notes show AAPL", "notes set AAPL \"Services margin above 70%\"", "notes show SAN:EPA", "notes export ~/notes"],
|
|
21
23
|
},
|
|
22
|
-
execute: async (
|
|
24
|
+
execute: async (rawArgs, ctx) => {
|
|
25
|
+
const args = [...rawArgs];
|
|
26
|
+
const exchange = takeOption(args, "--exchange");
|
|
27
|
+
// A note belongs to one listing: SAN:EPA, or SAN with --exchange EPA.
|
|
28
|
+
const noteSymbol = async (usage: string) => (
|
|
29
|
+
await requireListingArg(requireArg(args[1], usage, ctx), exchange, ctx)
|
|
30
|
+
).key;
|
|
23
31
|
await withConfigData(ctx, async (config) => {
|
|
24
32
|
const notes = new NotesFiles(config.dataDir);
|
|
25
33
|
const action = args[0] ?? "list";
|
|
@@ -62,14 +70,14 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
62
70
|
return;
|
|
63
71
|
}
|
|
64
72
|
if (action === "show") {
|
|
65
|
-
const symbol =
|
|
73
|
+
const symbol = await noteSymbol("Usage: gloomberb notes show <symbol>");
|
|
66
74
|
ctx.printResult({ data: { symbol, text: await notes.load(symbol) } }, {
|
|
67
75
|
text: (data) => data.text?.trim() ? data.text.trimEnd() : cliStyles.muted(`No note for ${symbol}.`),
|
|
68
76
|
});
|
|
69
77
|
return;
|
|
70
78
|
}
|
|
71
79
|
if (action === "set") {
|
|
72
|
-
const symbol =
|
|
80
|
+
const symbol = await noteSymbol("Usage: gloomberb notes set <symbol> <text...>");
|
|
73
81
|
const text = args.slice(2).join(" ");
|
|
74
82
|
if (!ctx.cliOptions.dryRun) await notes.save(symbol, text);
|
|
75
83
|
ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, symbol, bytes: text.length } }, {
|
|
@@ -78,7 +86,7 @@ export const notesCliCommand: CliCommandDef = {
|
|
|
78
86
|
return;
|
|
79
87
|
}
|
|
80
88
|
if (action === "delete" || action === "rm") {
|
|
81
|
-
const symbol =
|
|
89
|
+
const symbol = await noteSymbol("Usage: gloomberb notes delete <symbol>");
|
|
82
90
|
// Only picks the message; an unreadable note is still deleted.
|
|
83
91
|
const existed = await notes.load(symbol).then((text) => !!text?.trim(), () => true);
|
|
84
92
|
if (!ctx.cliOptions.dryRun) await notes.delete(symbol);
|
|
@@ -39,6 +39,7 @@ function report(draft: OptionCalcDraft, valuation: OptionValuation | null,
|
|
|
39
39
|
],
|
|
40
40
|
complete: valuation !== null && errors.length === 0,
|
|
41
41
|
errors, unavailableSymbols: surface?.error && draft.symbol ? [draft.symbol] : [],
|
|
42
|
+
...(surface ? { freshness: { source: "Your inputs and Gloom Cloud volatility" } } : {}),
|
|
42
43
|
metadata: { model, inputs: draft, valuation, impliedVolatility: implied, surface, effectiveTreeSteps,
|
|
43
44
|
warnings: surface?.warnings ?? [], method: model === "american" ? "CRR American tree with discrete cash dividends" : "European Black-Scholes",
|
|
44
45
|
greekUnits: { delta: "underlying units per option unit", gamma: "delta per underlying price unit", theta: "currency per calendar day",
|
|
@@ -49,6 +50,7 @@ function report(draft: OptionCalcDraft, valuation: OptionValuation | null,
|
|
|
49
50
|
|
|
50
51
|
export const optionsCalculatorHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
51
52
|
shape: "bundle", argument: { kind: "none" }, describe: "OVME option valuation",
|
|
53
|
+
freshness: { source: "Your inputs", status: "not-a-feed", basis: "calculator" },
|
|
52
54
|
discovery: { limitations: ["Discrete dividends use days from valuation and cash per underlying unit; model values exclude fees and assignment costs."] },
|
|
53
55
|
options: [
|
|
54
56
|
{ key: "model", type: "enum", values: [{ value: "european" }, { value: "american" }], defaultValue: "european", description: "European closed form or American CRR tree" },
|
|
@@ -23,6 +23,7 @@ const gamma = (value: unknown) => formatGamma(typeof value === "number" ? value
|
|
|
23
23
|
/** OPX opens on Strikes, GEX on its own tab; the report carries every section either way. */
|
|
24
24
|
export const optionsPositioningHeadless = (initialTab: PositioningTab): HeadlessPaneDefinition<"bundle"> => ({
|
|
25
25
|
shape: "bundle",
|
|
26
|
+
freshness: { status: "not-a-feed", basis: "daily open interest", cadence: "daily" },
|
|
26
27
|
argument: { kind: "ticker", optional: true, description: "US option underlying, or SPX; SPY when omitted" },
|
|
27
28
|
describe: (args) => `${initialTab === "gex" ? "GEX" : "OPX"} ${args.symbols[0] ?? "SPY"}`,
|
|
28
29
|
discovery: {
|
|
@@ -59,6 +60,8 @@ export const optionsPositioningHeadless = (initialTab: PositioningTab): Headless
|
|
|
59
60
|
];
|
|
60
61
|
const changes = openInterest.previousOiDate != null;
|
|
61
62
|
return {
|
|
63
|
+
// Open interest is published once a day for the prior session; the spot beside it is context.
|
|
64
|
+
freshness: { asOf: openInterest.oiDate },
|
|
62
65
|
sections: [
|
|
63
66
|
{ title: `Expiries · OI as of ${openInterest.oiDate ?? "--"}`, columns: [
|
|
64
67
|
{ key: "date", header: "Expiry" }, { key: "days", header: "Days" },
|
|
@@ -57,7 +57,12 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
57
57
|
// A seeded strategy starts at the spot its quote mids imply; the last print is reported beside it.
|
|
58
58
|
const lastPrint = midVolatility && !supplied(settings.spot) && market.spot != null && money(market.spot) !== money(position!.spot)
|
|
59
59
|
? market.spot : null;
|
|
60
|
+
const chain = market.chain;
|
|
60
61
|
return {
|
|
62
|
+
freshness: suppliedInputs
|
|
63
|
+
? { source: "Your inputs", status: "not-a-feed", basis: "scenario" }
|
|
64
|
+
: { asOf: market.asOf, ...(chain?.dataSource === "live" || chain?.dataSource === "delayed" ? { status: chain.dataSource } : {}),
|
|
65
|
+
...(chain?.delayMinutes ? { delayMinutes: chain.delayMinutes } : {}) },
|
|
61
66
|
sections: scenario ? [
|
|
62
67
|
{ title: "Position", columns: [
|
|
63
68
|
{ key: "side", header: "Side" }, { key: "strike", header: "Strike" }, { key: "expiry", header: "Expiry" },
|