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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatPriceEarnings } from "../../../utils/price-earnings";
|
|
1
|
+
import { formatPriceEarnings, NOT_MEANINGFUL } from "../../../utils/price-earnings";
|
|
2
2
|
import { useCallback, useMemo, useState } from "react";
|
|
3
3
|
import { TextAttributes } from "../../../ui";
|
|
4
4
|
import {
|
|
@@ -198,9 +198,9 @@ export function RelativeValuationPane({ focused, width, height }: PaneProps) {
|
|
|
198
198
|
case "marketCap":
|
|
199
199
|
return { text: formatCompact(row.marketCap ?? undefined, { fixedDecimals: true }), color: colors.textDim };
|
|
200
200
|
case "trailingPE":
|
|
201
|
-
return { text: formatPriceEarnings(row.reportedMultiples.trailingPE), color: colors.text };
|
|
201
|
+
return { text: formatPriceEarnings(row.notMeaningful.trailingPE ? NOT_MEANINGFUL : row.reportedMultiples.trailingPE), color: colors.text };
|
|
202
202
|
case "forwardPE":
|
|
203
|
-
return { text: formatPriceEarnings(row.reportedMultiples.forwardPE), color: colors.text };
|
|
203
|
+
return { text: formatPriceEarnings(row.notMeaningful.forwardPE ? NOT_MEANINGFUL : row.reportedMultiples.forwardPE), color: colors.text };
|
|
204
204
|
case "evSales":
|
|
205
205
|
return { text: formatNumber(row.evSales ?? undefined, 1), color: colors.text };
|
|
206
206
|
case "fcfYield":
|
|
@@ -2,9 +2,11 @@ import type { RevenueBreakdownView } from "../../../api-client/revenue-breakdown
|
|
|
2
2
|
import type { HeadlessPaneDefinition } from "../../../types/plugin";
|
|
3
3
|
import { fetchRevenueBreakdown } from "./client";
|
|
4
4
|
import { quarterLabel, reportedSpan } from "./model";
|
|
5
|
+
import { SEC_FILINGS } from "../shared/report-freshness";
|
|
5
6
|
|
|
6
7
|
export const revenueBreakdownHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
7
8
|
shape: "bundle",
|
|
9
|
+
freshness: { ...SEC_FILINGS, basis: "10-Q and 10-K filings" },
|
|
8
10
|
argument: {
|
|
9
11
|
kind: "ticker",
|
|
10
12
|
description: "SEC reporting issuer ticker.",
|
|
@@ -9,6 +9,7 @@ const implied = (value: ImpliedGrowth | null) => !value ? null : value.kind ===
|
|
|
9
9
|
|
|
10
10
|
export const reverseDcfHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
11
11
|
shape: "bundle", argument: { kind: "ticker", description: "Ticker" },
|
|
12
|
+
freshness: { status: "not-a-feed", basis: "price and reported cash flows" },
|
|
12
13
|
describe: (args) => `RDCF ${args.symbols[0] ?? ""}`,
|
|
13
14
|
discovery: { screenshotReadiness: "live-dom", limitations: ["Trailing twelve-month free cash flow against the reported enterprise value."] },
|
|
14
15
|
options: [
|
|
@@ -35,6 +36,7 @@ export const reverseDcfHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
35
36
|
...Object.fromEntries(row.implied.map((value, index) => [`t${index}`, implied(value)])) })) },
|
|
36
37
|
],
|
|
37
38
|
complete: !inputs.stale && !inputs.error && !model.error,
|
|
39
|
+
...(inputs.stale ? { freshness: { status: "stale" as const } } : {}),
|
|
38
40
|
unavailableSymbols: model.implied ? [] : [instrument.symbol],
|
|
39
41
|
errors: [inputs.error, model.error].filter((value): value is string => !!value),
|
|
40
42
|
metadata: { currency: model.currency, discountRate, terminalGrowth: TERMINAL_GROWTH, discountRates: DISCOUNT_RATES,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { HeadlessBundleSection, HeadlessPaneDefinition } from "../../../types/plugin";
|
|
2
2
|
import { loadRiskReportWithClient, loadRiskReportsWithClient, type RiskReportsResult } from "./data";
|
|
3
|
+
import { SEC_FILINGS } from "../shared/report-freshness";
|
|
3
4
|
|
|
4
5
|
export const riskFactorsHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
5
6
|
shape: "bundle",
|
|
7
|
+
freshness: { ...SEC_FILINGS, basis: "10-K filings" },
|
|
6
8
|
argument: { kind: "ticker", placeholder: "ticker", description: "Company symbol." },
|
|
7
9
|
options: [
|
|
8
10
|
{ key: "year", type: "string", defaultValue: "latest", description: "Filing year (for example 2025), or latest discovered report." },
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type ScannerFlowHistoryPage,
|
|
6
6
|
type ScannerFlowHistoryQuery,
|
|
7
7
|
} from "../../../api-client";
|
|
8
|
+
import { signalWithTimeout } from "../../../utils/async-deadline";
|
|
8
9
|
import { flowHistorySearch, mergeFlowRows } from "./flow-model";
|
|
9
10
|
|
|
10
11
|
export interface FlowHistoryState {
|
|
@@ -21,20 +22,8 @@ export type FlowHistoryLoader = (
|
|
|
21
22
|
signal: AbortSignal,
|
|
22
23
|
) => Promise<ScannerFlowHistoryPage>;
|
|
23
24
|
|
|
24
|
-
/** Aborts on the caller's signal or after `ms`; AbortSignal.any is too new for older system WebViews. */
|
|
25
|
-
function withTimeout(signal: AbortSignal, ms: number): AbortSignal {
|
|
26
|
-
const controller = new AbortController();
|
|
27
|
-
const abort = () => controller.abort();
|
|
28
|
-
if (signal.aborted) abort();
|
|
29
|
-
else signal.addEventListener("abort", abort, { once: true });
|
|
30
|
-
const timeout = AbortSignal.timeout(ms);
|
|
31
|
-
if (timeout.aborted) abort();
|
|
32
|
-
else timeout.addEventListener("abort", abort, { once: true });
|
|
33
|
-
return controller.signal;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
25
|
const loadRecordedPrints: FlowHistoryLoader = (query, signal) =>
|
|
37
|
-
apiClient.getScannerFlowHistory(flowHistorySearch(query),
|
|
26
|
+
apiClient.getScannerFlowHistory(flowHistorySearch(query), signalWithTimeout(signal, 20_000));
|
|
38
27
|
|
|
39
28
|
function emptyHistory(key: string): FlowHistoryState {
|
|
40
29
|
return { key, events: [], hasMore: true, loading: false, error: null };
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
import type {
|
|
8
8
|
HeadlessPaneApiClient,
|
|
9
9
|
HeadlessPaneDefinition,
|
|
10
|
+
HeadlessPaneFreshness,
|
|
10
11
|
HeadlessPaneLoadArgs,
|
|
11
12
|
HeadlessPaneOptionDef,
|
|
12
13
|
HeadlessSnapshotResult,
|
|
@@ -88,6 +89,17 @@ export function loadHiloSnapshot(
|
|
|
88
89
|
return loadScannerSnapshot<ScannerHiloPayload>(client, "hilo", signal, timeoutMs);
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* The scanner says which instance served it, real-time or the delayed one free
|
|
94
|
+
* accounts get, and whether it is running: a closed session's scan is final,
|
|
95
|
+
* and a degraded one may have fallen behind.
|
|
96
|
+
*/
|
|
97
|
+
function scannerFreshness(payload: Pick<ScannerHiloPayload, "access" | "delayMinutes" | "status">): HeadlessPaneFreshness {
|
|
98
|
+
if (payload.status === "closed") return { status: "not-a-feed", basis: "closed session" };
|
|
99
|
+
if (payload.status === "degraded") return { status: "stale" };
|
|
100
|
+
return payload.access === "realtime" ? { status: "live" } : { status: "delayed", delayMinutes: payload.delayMinutes };
|
|
101
|
+
}
|
|
102
|
+
|
|
91
103
|
function projectHiloSnapshot(
|
|
92
104
|
payload: ScannerHiloPayload,
|
|
93
105
|
minPrice: HiloMinPrice,
|
|
@@ -99,6 +111,7 @@ function projectHiloSnapshot(
|
|
|
99
111
|
asOf: new Date(payload.asOf).toISOString(),
|
|
100
112
|
items: [...lows, ...highs],
|
|
101
113
|
...(payload.status === "degraded" ? { errors: ["Scanner feed degraded"] } : {}),
|
|
114
|
+
freshness: scannerFreshness(payload),
|
|
102
115
|
metadata: {
|
|
103
116
|
...(payload.access === "delayed" ? { notices: [`Delayed ${payload.delayMinutes} minutes`] } : {}),
|
|
104
117
|
status: payload.status,
|
|
@@ -214,6 +227,7 @@ function projectFlowSnapshot(
|
|
|
214
227
|
asOf: new Date(payload.asOf).toISOString(),
|
|
215
228
|
items: events.map((event) => ({ ...event })),
|
|
216
229
|
...(payload.status === "degraded" ? { errors: ["Scanner feed degraded"] } : {}),
|
|
230
|
+
freshness: scannerFreshness(payload),
|
|
217
231
|
metadata: {
|
|
218
232
|
status: payload.status,
|
|
219
233
|
access: payload.access,
|
|
@@ -7,6 +7,8 @@ const percent = (value: unknown) => typeof value === "number" ? `${(value * 100)
|
|
|
7
7
|
|
|
8
8
|
export const seasonalityHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
9
9
|
shape: "bundle", argument: { kind: "ticker", description: "Ticker" },
|
|
10
|
+
// Dated by the month of its last monthly close.
|
|
11
|
+
freshness: { status: "not-a-feed", basis: "monthly closes", maxAgeMinutes: 45 * 24 * 60 },
|
|
10
12
|
describe: (args) => `SEAS ${args.symbols[0] ?? ""}`,
|
|
11
13
|
discovery: { screenshotReadiness: "live-dom", limitations: ["Local-price closes; dividends and FX are excluded."] },
|
|
12
14
|
options: [
|
|
@@ -116,6 +116,19 @@ function requestSecFilingFocus(symbol: string, accessionNumber: string): void {
|
|
|
116
116
|
for (const listener of listeners.values()) listener(accessionNumber);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Opens a filing in the SEC pane for `symbol`, reusing an open one, the way a
|
|
121
|
+
* filing row in the command bar does.
|
|
122
|
+
*/
|
|
123
|
+
export function openSecFilingInPane(
|
|
124
|
+
ctx: Pick<GloomPluginContext, "createPaneFromTemplate">,
|
|
125
|
+
symbol: string,
|
|
126
|
+
accessionNumber: string,
|
|
127
|
+
): void {
|
|
128
|
+
requestSecFilingFocus(symbol, accessionNumber);
|
|
129
|
+
void ctx.createPaneFromTemplate(SEC_TEMPLATE_ID, { symbol });
|
|
130
|
+
}
|
|
131
|
+
|
|
119
132
|
export function useSecFilingFocusRequest(symbol: string | null | undefined, onFocus: FocusListener): void {
|
|
120
133
|
const [view] = useState(() => ({}));
|
|
121
134
|
useEffect(() => {
|
|
@@ -173,10 +186,7 @@ function filingRow(
|
|
|
173
186
|
badge: filing.form.replace(/\s+/g, "").slice(0, 6),
|
|
174
187
|
right: filingDateLabel(filedAt(filing), now),
|
|
175
188
|
keywords: [ticker, filing.form],
|
|
176
|
-
execute: () =>
|
|
177
|
-
requestSecFilingFocus(ticker, filing.accessionNumber);
|
|
178
|
-
void ctx.createPaneFromTemplate(SEC_TEMPLATE_ID, { symbol: ticker });
|
|
179
|
-
},
|
|
189
|
+
execute: () => openSecFilingInPane(ctx, ticker, filing.accessionNumber),
|
|
180
190
|
};
|
|
181
191
|
}
|
|
182
192
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useSecFilingContent } from "../../../market-data/hooks";
|
|
3
3
|
import { getSharedMarketDataCoordinator, resolveEntryValue } from "../../../market-data/coordinator";
|
|
4
|
+
import type { QueryEntry } from "../../../market-data/result-types";
|
|
4
5
|
import type { SecFilingDocument, SecFilingItem } from "../../../types/data-provider";
|
|
5
6
|
import { documentContentTarget, isInlineExhibitDocument } from "./filing-documents";
|
|
6
7
|
|
|
@@ -14,6 +15,22 @@ interface ScopedFilingContentCache {
|
|
|
14
15
|
const EMPTY_CONTENT_CACHE = new Map<string, string | null>();
|
|
15
16
|
const EMPTY_ERRORS = new Map<string, string>();
|
|
16
17
|
|
|
18
|
+
/** What a finished content entry holds, or null while it is still loading. */
|
|
19
|
+
function settledFilingContent(
|
|
20
|
+
entry: QueryEntry<string | null> | null | undefined,
|
|
21
|
+
): { content: string | null; error: string | null } | null {
|
|
22
|
+
if (!entry) return null;
|
|
23
|
+
const resolved = resolveEntryValue(entry);
|
|
24
|
+
const settled = entry.phase === "ready"
|
|
25
|
+
|| entry.phase === "error"
|
|
26
|
+
|| (entry.phase === "refreshing" && resolved !== null);
|
|
27
|
+
if (!settled) return null;
|
|
28
|
+
return {
|
|
29
|
+
content: entry.phase === "error" ? null : resolved,
|
|
30
|
+
error: entry.error?.reasonCode === "NO_DATA" ? null : entry.error?.message ?? null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
17
34
|
export function buildInlineFilingContentTargets(
|
|
18
35
|
filing: SecFilingItem | null | undefined,
|
|
19
36
|
documents: readonly SecFilingDocument[],
|
|
@@ -69,28 +86,36 @@ export function useSecFilingContentCache({
|
|
|
69
86
|
[contentCache, targets],
|
|
70
87
|
);
|
|
71
88
|
const contentEntry = useSecFilingContent(nextTarget);
|
|
72
|
-
const resolvedContent = useResolvedEntryValue(contentEntry);
|
|
73
89
|
|
|
74
90
|
useEffect(() => {
|
|
75
91
|
if (!nextTarget) return;
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|| (phase === "refreshing" && resolvedContent !== null);
|
|
80
|
-
if (!settled) return;
|
|
81
|
-
const key = nextTarget.accessionNumber;
|
|
82
|
-
const content = phase === "error" ? null : resolvedContent;
|
|
83
|
-
const error = contentEntry?.error?.reasonCode === "NO_DATA" ? null : contentEntry?.error?.message;
|
|
92
|
+
const first = settledFilingContent(contentEntry);
|
|
93
|
+
if (!first) return;
|
|
94
|
+
const coordinator = getSharedMarketDataCoordinator();
|
|
84
95
|
setState((current) => {
|
|
85
|
-
if (current.scopeKey !== scopeKey
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
if (current.scopeKey !== scopeKey) return current;
|
|
97
|
+
let values = current.values;
|
|
98
|
+
let errors = current.errors;
|
|
99
|
+
const record = (key: string, settled: { content: string | null; error: string | null }) => {
|
|
100
|
+
if (values === current.values) values = new Map(values);
|
|
101
|
+
values.set(key, settled.content);
|
|
102
|
+
if (!settled.error) return;
|
|
103
|
+
if (errors === current.errors) errors = new Map(errors);
|
|
104
|
+
errors.set(key, settled.error);
|
|
91
105
|
};
|
|
106
|
+
if (!values.has(nextTarget.accessionNumber)) record(nextTarget.accessionNumber, first);
|
|
107
|
+
// Content the coordinator already holds (a pane reopened, a ticker
|
|
108
|
+
// visited again) is taken in this same update. Taken one target per
|
|
109
|
+
// render, each one would expose the next, and a few dozen filings chain
|
|
110
|
+
// that many renders in a row, past React's limit of 50 nested updates.
|
|
111
|
+
for (const target of targets) {
|
|
112
|
+
if (values.has(target.accessionNumber)) continue;
|
|
113
|
+
const settled = settledFilingContent(coordinator?.getSecContentEntry(target.accessionNumber));
|
|
114
|
+
if (settled) record(target.accessionNumber, settled);
|
|
115
|
+
}
|
|
116
|
+
return values === current.values ? current : { ...current, values, errors };
|
|
92
117
|
});
|
|
93
|
-
}, [contentEntry
|
|
118
|
+
}, [contentEntry, nextTarget, scopeKey, targets]);
|
|
94
119
|
|
|
95
120
|
// Successful accession content is immutable. Retry only selected documents
|
|
96
121
|
// that failed or had no readable content, preserving the sequential queue.
|
|
@@ -52,3 +52,15 @@ export function filterFilingsByForms(filings: readonly SecFilingItem[], forms: r
|
|
|
52
52
|
return accepted.has(form) || (form.endsWith("/A") && accepted.has(form.slice(0, -2)));
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
+
|
|
56
|
+
/** A form as typed or filed, without punctuation or the `SC`/`SCHEDULE` prefix of ownership schedules. */
|
|
57
|
+
function compactFilingForm(form: string): string {
|
|
58
|
+
return form.toUpperCase().replace(/[^A-Z0-9]/g, "").replace(/^(?:SCHEDULE|SC)(?=\d)/, "");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** `13D` matches SC 13D, SCHEDULE 13D and their amendments; `10-K` matches 10-K and 10-K/A. */
|
|
62
|
+
export function filingFormMatches(form: string, wanted: string): boolean {
|
|
63
|
+
const target = compactFilingForm(wanted);
|
|
64
|
+
const actual = compactFilingForm(form);
|
|
65
|
+
return !!target && (actual === target || actual === `${target}A`);
|
|
66
|
+
}
|
|
@@ -8,6 +8,7 @@ import type { SecFilingItem } from "../../../types/data-provider";
|
|
|
8
8
|
import { loadSecFilings } from "./client";
|
|
9
9
|
import { filterFilingsByForms, SEC_FILING_FETCH_LIMIT } from "./forms";
|
|
10
10
|
import { buildSecFilingRows, secFilingIssuers, SEC_ACCEPTANCE_NOTE } from "./model";
|
|
11
|
+
import { SEC_FILINGS } from "../shared/report-freshness";
|
|
11
12
|
|
|
12
13
|
const SEC_COLUMNS: HeadlessPaneColumn[] = [
|
|
13
14
|
{
|
|
@@ -49,6 +50,7 @@ export function createSecHeadless(
|
|
|
49
50
|
): HeadlessPaneDefinition<"rows"> {
|
|
50
51
|
return {
|
|
51
52
|
shape: "rows",
|
|
53
|
+
freshness: { ...SEC_FILINGS, observedKey: "acceptedAt" },
|
|
52
54
|
argument: {
|
|
53
55
|
kind: "ticker",
|
|
54
56
|
placeholder: "ticker",
|
|
@@ -87,6 +87,7 @@ export async function loadSectorRows(
|
|
|
87
87
|
quoteIssue,
|
|
88
88
|
lastReportedPrice,
|
|
89
89
|
quoteUpdatedAt: quote && Number.isFinite(quote.lastUpdated) ? quote.lastUpdated : null,
|
|
90
|
+
quoteDataSource: quote?.dataSource,
|
|
90
91
|
changePercent,
|
|
91
92
|
return1M: month?.value ?? null,
|
|
92
93
|
return1Y: year?.value ?? null,
|
|
@@ -32,6 +32,8 @@ export function projectSectorRows(
|
|
|
32
32
|
loading: false,
|
|
33
33
|
quoteUnavailable: !byEtf.get(definition.etf) || byEtf.get(definition.etf)?.quoteUnavailable === true,
|
|
34
34
|
quoteSessionDate: byEtf.get(definition.etf)?.quoteSessionDate ?? null,
|
|
35
|
+
quoteUpdatedAt: byEtf.get(definition.etf)?.quoteUpdatedAt ?? null,
|
|
36
|
+
quoteDataSource: byEtf.get(definition.etf)?.quoteDataSource,
|
|
35
37
|
quoteIssue: byEtf.get(definition.etf)?.quoteIssue ?? null,
|
|
36
38
|
lastReportedPrice: byEtf.get(definition.etf)?.lastReportedPrice ?? null,
|
|
37
39
|
returnIntegrity: byEtf.get(definition.etf)?.returnIntegrity ?? {},
|
|
@@ -58,6 +60,8 @@ export function createSectorsHeadless(
|
|
|
58
60
|
): HeadlessPaneDefinition<"rows"> {
|
|
59
61
|
return {
|
|
60
62
|
shape: "rows",
|
|
63
|
+
// Dated by each ETF's quote; the shared session date is the returns' end, not an observation.
|
|
64
|
+
freshness: { observedKey: "quoteUpdatedAt" },
|
|
61
65
|
argument: { kind: "none" },
|
|
62
66
|
options: [{
|
|
63
67
|
key: "collection",
|
|
@@ -81,7 +85,11 @@ export function createSectorsHeadless(
|
|
|
81
85
|
return {
|
|
82
86
|
unavailableSymbols: unavailableSymbols.length > 0 ? unavailableSymbols : undefined,
|
|
83
87
|
errors: rows.flatMap((row) => sectorRowIssues(row).map((issue) => `${row.etf}: ${issue}.`)),
|
|
84
|
-
|
|
88
|
+
// The quote behind each row says whether it is real-time or delayed, and how current it is.
|
|
89
|
+
rows: rows.map(({ quoteDataSource, ...row }) => ({
|
|
90
|
+
...row,
|
|
91
|
+
...(quoteDataSource === "live" || quoteDataSource === "delayed" ? { dataSource: quoteDataSource } : {}),
|
|
92
|
+
})),
|
|
85
93
|
metadata: {
|
|
86
94
|
collection: collectionId,
|
|
87
95
|
available: outcomes.filter((outcome) => outcome.row).length,
|
|
@@ -25,6 +25,8 @@ export interface SectorRow extends SectorDef {
|
|
|
25
25
|
lastReportedPrice?: number | null;
|
|
26
26
|
/** When the snapshot quote behind `price` was stamped; a live quote must be at least as new. */
|
|
27
27
|
quoteUpdatedAt?: number | null;
|
|
28
|
+
/** Whether that quote is real-time or delayed, for the report's freshness line. */
|
|
29
|
+
quoteDataSource?: Quote["dataSource"];
|
|
28
30
|
returnIntegrity?: Partial<Record<SectorReturnRange, PriceHistoryIntegrity>>;
|
|
29
31
|
returnAsOfDate?: string | null;
|
|
30
32
|
return1MStartDate?: string | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The coin a USD crypto pair names: BTC-USD gives BTC. CME lists bitcoin and
|
|
3
|
+
* ether futures, but BTC and ETH are also US equity tickers (Grayscale's mini
|
|
4
|
+
* trusts), so a futures function that falls back to the ticker under the
|
|
5
|
+
* cursor reads a bare symbol as the equity and only a pair as the coin.
|
|
6
|
+
*/
|
|
7
|
+
export function cryptoPairCoin(ticker: string): string | null {
|
|
8
|
+
return /^([A-Z0-9]{2,10})-USD$/.exec(ticker.trim().toUpperCase())?.[1] ?? null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** `BTC=F`: the spelling of a futures contract, which no equity shares. */
|
|
12
|
+
export function isFuturesSymbol(ticker: string): boolean {
|
|
13
|
+
return ticker.trim().toUpperCase().endsWith("=F");
|
|
14
|
+
}
|
|
@@ -20,7 +20,7 @@ export function Blurred({ children }: { children: ReactNode }) {
|
|
|
20
20
|
export function UpgradeLabel({ text, onPress, role }: { text: string; onPress: () => void; role?: string }) {
|
|
21
21
|
const colors = useThemeColors();
|
|
22
22
|
return (
|
|
23
|
-
<Box flexDirection="row" gap={1} onMouseDown={onPress} data-gloom-role={role}>
|
|
23
|
+
<Box flexDirection="row" gap={1} onMouseDown={onPress} data-gloom-role={role} data-gloom-ui="pro-lock">
|
|
24
24
|
<Icon name="lock" size={11} color={colors.textBright} />
|
|
25
25
|
<Text fg={colors.textBright}>{text}</Text>
|
|
26
26
|
</Box>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { HeadlessPaneFreshness } from "../../../types/headless";
|
|
2
|
+
import type { Quote } from "../../../types/financials";
|
|
3
|
+
import { isQuoteStaleForCurrentSession } from "../../../market-data/quotes/freshness";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Freshness declarations shared by built-in reports. Each `fn` report ends
|
|
7
|
+
* with the source, as-of and status line these feed; see
|
|
8
|
+
* docs/usage.md#how-current-a-report-is.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Analyses over end-of-day history: not a feed, but stale once the closes stop arriving. */
|
|
12
|
+
export const DAILY_CLOSES: HeadlessPaneFreshness = { status: "not-a-feed", basis: "daily closes", cadence: "daily" };
|
|
13
|
+
|
|
14
|
+
const DAY_MINUTES = 24 * 60;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Price bars: a history, not a feed, stale once the bars stop arriving for
|
|
18
|
+
* their size. Intraday and daily bars follow the US trading sessions; a
|
|
19
|
+
* weekly or monthly bar is dated by the start of its period.
|
|
20
|
+
*/
|
|
21
|
+
export function barHistoryFreshness(resolution: string | null | undefined): HeadlessPaneFreshness {
|
|
22
|
+
if (resolution === "1wk") return { status: "not-a-feed", basis: "weekly bars", maxAgeMinutes: 14 * DAY_MINUTES };
|
|
23
|
+
if (resolution === "1mo") return { status: "not-a-feed", basis: "monthly bars", maxAgeMinutes: 45 * DAY_MINUTES };
|
|
24
|
+
if (resolution === "1d") return DAILY_CLOSES;
|
|
25
|
+
return { status: "not-a-feed", basis: "intraday bars", cadence: "daily" };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The bar size of a dated history, read from the gap between its last two bars. */
|
|
29
|
+
export function barResolutionFromDates(dates: readonly (string | number | Date)[]): "1d" | "1wk" | "1mo" {
|
|
30
|
+
const times = dates.slice(-2).map((date) => new Date(date).getTime());
|
|
31
|
+
const gapDays = times.length === 2 && times.every(Number.isFinite) ? (times[1]! - times[0]!) / 86_400_000 : 1;
|
|
32
|
+
return gapDays >= 25 ? "1mo" : gapDays >= 6 ? "1wk" : "1d";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Company filings read from EDGAR. Old filings are not stale; there is no schedule to miss. */
|
|
36
|
+
export const SEC_FILINGS: HeadlessPaneFreshness = { source: "SEC EDGAR", status: "not-a-feed", basis: "filed data", oldest: null };
|
|
37
|
+
|
|
38
|
+
/** Places and listings that change only when someone edits them: venues, ports, pipelines. */
|
|
39
|
+
export const REFERENCE_DATA: HeadlessPaneFreshness = { status: "not-a-feed", basis: "reference data", oldest: null };
|
|
40
|
+
|
|
41
|
+
/** Company fundamentals, estimates and calendars: reported figures, not a feed. */
|
|
42
|
+
export const REPORTED_DATA: HeadlessPaneFreshness = { status: "not-a-feed", basis: "reported data" };
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The standard freshness fields of one quote, spread into a report row so the
|
|
46
|
+
* report can say whether that row is live, delayed or stale for its session.
|
|
47
|
+
*/
|
|
48
|
+
export function quoteFreshnessFields(
|
|
49
|
+
quote: Quote | null | undefined,
|
|
50
|
+
now = Date.now(),
|
|
51
|
+
): { dataSource?: "live" | "delayed"; stale?: boolean } {
|
|
52
|
+
if (!quote) return {};
|
|
53
|
+
return {
|
|
54
|
+
...(quote.dataSource === "live" || quote.dataSource === "delayed" ? { dataSource: quote.dataSource } : {}),
|
|
55
|
+
stale: isQuoteStaleForCurrentSession(quote, now),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DataTableCell, DataTableColumn } from "../../../components";
|
|
2
|
+
import { RatioBar } from "../../../components/ui/ratio-bar";
|
|
2
3
|
import { SplitBar } from "../../../components/ui/split-bar";
|
|
3
4
|
import { blendHex } from "../../../theme/colors";
|
|
4
5
|
import type { ThemeColors } from "../../../theme/colors";
|
|
@@ -39,21 +40,15 @@ export function listingCell(key: string | null | undefined, colors: ThemeColors,
|
|
|
39
40
|
* so the eye compares lengths down the column. The bar gives way first in a
|
|
40
41
|
* narrow column; the number never does.
|
|
41
42
|
*/
|
|
42
|
-
export function shareCell(text: string, ratio: number | null, width: number, colors: ThemeColors, selected: boolean,
|
|
43
|
+
export function shareCell(text: string, ratio: number | null, width: number, colors: ThemeColors, selected: boolean,
|
|
43
44
|
color = blendHex(colors.bg, colors.borderFocused, 0.6)): DataTableCell {
|
|
44
45
|
const textCells = displayWidth(text);
|
|
45
46
|
const barCells = width - textCells - 1;
|
|
46
47
|
if (ratio == null || !(ratio > 0) || barCells < 4) return { text, color: selected ? colors.selectedText : colors.text };
|
|
47
|
-
|
|
48
|
-
const ink = selected ? colors.selectedText : color;
|
|
49
|
-
// The desktop draws the bar on a faint track; terminal cells draw the length alone, at half-cell steps,
|
|
48
|
+
// The desktop draws the bar on a faint track; terminal cells draw the length alone,
|
|
50
49
|
// since a track of block cells would join the rows above and below into one wall.
|
|
51
|
-
const units = Math.max(1, Math.round(fill * barCells * 2));
|
|
52
50
|
return { text, content: <Box flexDirection="row" height={1} width={width} overflow="hidden" alignItems="center">
|
|
53
|
-
<
|
|
54
|
-
{desktop ? <SplitBar width={barCells} parts={[{ id: "share", value: fill, color: ink }, { id: "rest", value: 1 - fill, color: blendHex(colors.bg, color, 0.2) }]} />
|
|
55
|
-
: <Text fg={ink}>{`${"█".repeat(Math.floor(units / 2))}${units % 2 ? "▌" : ""}`}</Text>}
|
|
56
|
-
</Box>
|
|
51
|
+
<RatioBar ratio={ratio} width={barCells} color={selected ? colors.selectedText : color} track />
|
|
57
52
|
<Box flexGrow={1} justifyContent="flex-end"><Text fg={selected ? colors.selectedText : colors.text}>{` ${text}`}</Text></Box>
|
|
58
53
|
</Box> };
|
|
59
54
|
}
|
|
@@ -58,6 +58,8 @@ export function createShortInterestHeadless(
|
|
|
58
58
|
): HeadlessPaneDefinition<"rows"> {
|
|
59
59
|
return {
|
|
60
60
|
shape: "rows",
|
|
61
|
+
// Settled twice a month and published about a week later; a month without one has missed it.
|
|
62
|
+
freshness: { source: "FINRA", status: "not-a-feed", basis: "twice-monthly settlement", observedKey: "settlementDate", oldest: null, maxAgeMinutes: 30 * 24 * 60 },
|
|
61
63
|
argument: {
|
|
62
64
|
kind: "ticker",
|
|
63
65
|
placeholder: "ticker",
|
|
@@ -10,6 +10,7 @@ const signedPercent = (value: unknown) =>
|
|
|
10
10
|
|
|
11
11
|
export const shortWatchHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
12
12
|
shape: "rows",
|
|
13
|
+
freshness: { source: "FINRA", status: "not-a-feed", basis: "twice-monthly settlement", observedKey: "settlementDate", maxAgeMinutes: 30 * 24 * 60 },
|
|
13
14
|
argument: { kind: "symbol-list", maximum: SHORT_WATCH_LIMIT, description: "US tickers; the pane defaults to your portfolios and watchlists." },
|
|
14
15
|
options: [],
|
|
15
16
|
describe: "Short squeeze watch",
|
|
@@ -4,6 +4,7 @@ import { volumePercent, volumePointStatus, volumeQuantity } from "./model";
|
|
|
4
4
|
|
|
5
5
|
export const shortVolumeHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
6
6
|
shape: "bundle", argument: { kind: "ticker", description: "US equity ticker.", placeholder: "ticker" },
|
|
7
|
+
freshness: { source: "FINRA", status: "not-a-feed", basis: "daily short volume", cadence: "daily", observedKey: "date", oldest: null },
|
|
7
8
|
discovery: { aliases: ["SIV"], dataRequirements: ["Gloom Cloud FINRA daily short volume"],
|
|
8
9
|
limitations: ["Regular-session off-exchange volume, not short interest", "Short volume includes exempt volume", "One-year history depends on source discovery and ingestion"] },
|
|
9
10
|
options: [
|
|
@@ -5,6 +5,7 @@ import { socialCount, socialDayRows, socialRatio, socialStance, topPostCell } fr
|
|
|
5
5
|
|
|
6
6
|
export const socialMentionsHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
7
7
|
shape: "bundle", argument: { kind: "ticker", description: "Ticker with a searchable cashtag (up to six letters and digits).", placeholder: "ticker" },
|
|
8
|
+
freshness: { source: "X posts", status: "not-a-feed", basis: "daily post counts" },
|
|
8
9
|
discovery: { aliases: ["BUZZ"], dataRequirements: ["Gloom Cloud X mention history"],
|
|
9
10
|
limitations: ["Daily $cashtag posts on X in UTC days, spam included", "Top posts and stance cover days that were looked up", "Views exist from 2022-12-22"] },
|
|
10
11
|
options: [
|
|
@@ -4,6 +4,7 @@ import { fetchSupplyChain } from "./client";
|
|
|
4
4
|
import { evidenceLabel, isUnconfirmed, matchesSupplyOptions, supplyOptions, trustTier } from "./trust";
|
|
5
5
|
import { fetchSupplyGraph, graphOptions } from "./graph-client";
|
|
6
6
|
import { exposureLabel, pathLabel } from "./graph-model";
|
|
7
|
+
import { supplyRoleCounts } from "./model";
|
|
7
8
|
|
|
8
9
|
const pathColumns = [
|
|
9
10
|
{ key: "route", header: "Route" }, { key: "hops", header: "Hops" },
|
|
@@ -54,6 +55,7 @@ function graphReport(data: GraphPayload, target: string): HeadlessBundleResult {
|
|
|
54
55
|
|
|
55
56
|
export const supplyChainHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
56
57
|
shape: "bundle",
|
|
58
|
+
freshness: { source: "Company filings, calls and news", status: "not-a-feed", basis: "disclosed relationships" },
|
|
57
59
|
argument: { kind: "ticker", description: "Company ticker, exchange-qualified ticker, or id:<entity-id>.", placeholder: "ticker" },
|
|
58
60
|
discovery: { aliases: ["SPLC", "SUPPLY"], dataRequirements: ["Gloom Cloud relationship evidence (Pro with free preview)"],
|
|
59
61
|
limitations: ["Filings, company announcements, earnings calls and news where evidence is available globally", "Japan filings await an API key and Taiwan report ingestion is disabled", "English glosses are machine translations, separate from original evidence", "Absence is not proof of no relationship",
|
|
@@ -87,6 +89,9 @@ export const supplyChainHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
87
89
|
}
|
|
88
90
|
const options = supplyOptions(args.options.tiers);
|
|
89
91
|
const data = await fetchSupplyChain(args.symbols[0]!, ctx.apiClient, options);
|
|
92
|
+
// The pane's figures, per tab: Table shows one direction, Flow both.
|
|
93
|
+
const figures = (key: "counterparties" | "locked") => Object.fromEntries(([["says", ["says"]], ["names", ["names"]], ["flow", ["says", "names"]]] as const)
|
|
94
|
+
.map(([scope, views]) => [scope, Object.fromEntries(supplyRoleCounts(data, views, options).filter((entry) => entry[key] > 0).map((entry) => [entry.role, entry[key]]))]));
|
|
90
95
|
return { complete: !data.truncated, errors: data.truncated ? ["Additional relationships need Gloom Pro"] : [],
|
|
91
96
|
sections: (["says", "names"] as const).flatMap((view) => [false, true].map((leads) => ({ title: `${view === "says" ? `${data.symbol} says` : `Names ${data.symbol}`}${leads ? " | Unconfirmed" : ""}`,
|
|
92
97
|
rows: data[view].filter((row) => matchesSupplyOptions(row, options) && isUnconfirmed(row) === leads).map((row) => ({ counterparty: row.counterparty.name, ticker: row.counterparty.ticker, aggregate: row.counterparty.aggregate, role: row.role, direction: row.direction,
|
|
@@ -100,6 +105,7 @@ export const supplyChainHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
100
105
|
quote: row.quote, quoteLanguage: row.quoteLanguage, quoteGloss: row.quoteGloss ?? null, quoteGlossKind: row.quoteGloss ? "machine_translation" : null,
|
|
101
106
|
quoteMatchMode: row.quoteMatchMode, sourceUrl: row.filingUrl, filingUrl: row.filingUrl, sectionRef: row.sectionRef ?? null, sourceAttribution: row.sourceAttribution ?? null,
|
|
102
107
|
evidence: row.evidence ?? [] })) })).filter((section) => section.rows.length > 0)),
|
|
103
|
-
metadata: { symbol: data.symbol, asOf: data.asOf,
|
|
108
|
+
metadata: { symbol: data.symbol, asOf: data.asOf, counterparties: figures("counterparties"), locked: figures("locked"),
|
|
109
|
+
counts: data.counts, tierCounts: data.tierCounts, tiers: options.tiers, disclaimer: data.disclaimer } };
|
|
104
110
|
},
|
|
105
111
|
};
|
|
@@ -5,6 +5,11 @@ import { supplyChainCache } from "./client";
|
|
|
5
5
|
import { supplyChainHeadless } from "./headless";
|
|
6
6
|
import { SupplyChainPane } from "./pane";
|
|
7
7
|
|
|
8
|
+
/** What another pane can open SPLC on: a Graph or Path view, its target and its query, as `graphOptions` reads them. */
|
|
9
|
+
const OPENING_SETTINGS = ["tab", "to", "depth", "direction", "roles", "tiers"];
|
|
10
|
+
const openingSettings = (values: Record<string, string> = {}) =>
|
|
11
|
+
Object.fromEntries(OPENING_SETTINGS.flatMap((key) => values[key] ? [[key, values[key]]] : []));
|
|
12
|
+
|
|
8
13
|
export const supplyChainModule: PluginModule = {
|
|
9
14
|
setup(ctx) { supplyChainCache.attach(ctx.persistence); graphCache.attach(ctx.persistence); },
|
|
10
15
|
dispose() { supplyChainCache.reset(); graphCache.reset(); },
|
|
@@ -13,5 +18,9 @@ export const supplyChainModule: PluginModule = {
|
|
|
13
18
|
tickerFollower: true, tableExport: true, headless: supplyChainHeadless }],
|
|
14
19
|
paneTemplates: [{ ...createTickerSurfacePaneTemplate({ id: "supply-chain-pane", paneId: "supply-chain", label: "Supply Chain",
|
|
15
20
|
description: "Pro global supply chain evidence from filings, company announcements, calls and news, with trust tiers, original quotes, native units, four-hop graphs, ranked paths and a free preview.",
|
|
16
|
-
keywords: ["supply", "supply chain", "suppliers", "customers", "concentration", "filings", "earnings calls", "news", "evidence", "global", "Korea", "Japan", "Taiwan", "graph", "paths", "Pro"], shortcut: "SPLC", shortcutAliases: ["SUPPLY"]
|
|
21
|
+
keywords: ["supply", "supply chain", "suppliers", "customers", "concentration", "filings", "earnings calls", "news", "evidence", "global", "Korea", "Japan", "Taiwan", "graph", "paths", "Pro"], shortcut: "SPLC", shortcutAliases: ["SUPPLY"],
|
|
22
|
+
settings: (_symbol, _context, options) => openingSettings(options?.values),
|
|
23
|
+
// A route opened from another pane gets a pane of its own, so the company's SPLC keeps its view.
|
|
24
|
+
viewKey: (_symbol, _context, options) => options?.values?.to ? `${options.values.tab ?? "graph"}:${options.values.to}` : undefined,
|
|
25
|
+
}), headless: supplyChainHeadless }],
|
|
17
26
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { SupplyRole, SupplyRow } from "../../../api-client/supply-chain";
|
|
1
|
+
import type { SupplyChainPayload, SupplyOptions, SupplyRole, SupplyRow } from "../../../api-client/supply-chain";
|
|
2
2
|
import { SERIES_COLORS } from "../../../time-series/resolve";
|
|
3
3
|
import { revenueAmount } from "../revenue-breakdown/model";
|
|
4
|
-
import { activeRelationship, corroborationLabel, evidenceDate, evidenceLabel, isUnconfirmed, trustTier } from "./trust";
|
|
4
|
+
import { activeRelationship, corroborationLabel, evidenceDate, evidenceLabel, isUnconfirmed, matchesSupplyOptions, trustTier } from "./trust";
|
|
5
5
|
|
|
6
6
|
/** One colour per role from the shared series palette, the same in the table, the flow and the evidence. */
|
|
7
7
|
export const ROLE_COLORS: Record<SupplyRole, string> = {
|
|
@@ -64,6 +64,31 @@ export function counterpartyName(row: SupplyRow): string {
|
|
|
64
64
|
return member ? `${member.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\s*\(undisclosed\)/gi, "")} (undisclosed)` : name;
|
|
65
65
|
}
|
|
66
66
|
export const roleLabel = (role: SupplyRole) => role[0]!.toUpperCase() + role.slice(1);
|
|
67
|
+
|
|
68
|
+
const SUPPLY_ROLE_ORDER: readonly SupplyRole[] = ["customer", "supplier", "partner", "competitor", "investee"];
|
|
69
|
+
export interface SupplyRoleCount { role: SupplyRole; counterparties: number; locked: number }
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The one count behind the figures over the table, the flow and the headless
|
|
73
|
+
* report: per role, the companies the reader can see, each counted once
|
|
74
|
+
* however many disclosures name it (the flow draws one card per counterparty
|
|
75
|
+
* and role). Unconfirmed leads, inactive links and cohort groups are not
|
|
76
|
+
* counterparties. The server's counts are disclosures, not companies, so what
|
|
77
|
+
* a free preview withholds is reported apart as locked disclosures rather
|
|
78
|
+
* than added to the companies.
|
|
79
|
+
*/
|
|
80
|
+
export function supplyRoleCounts(data: Pick<SupplyChainPayload, "says" | "names" | "counts">, views: readonly ("says" | "names")[], options: Required<SupplyOptions>): SupplyRoleCount[] {
|
|
81
|
+
return SUPPLY_ROLE_ORDER.map((role) => {
|
|
82
|
+
const companies = new Set<string>();
|
|
83
|
+
let locked = 0;
|
|
84
|
+
for (const view of views) {
|
|
85
|
+
const rows = data[view].filter((row) => row.role === role);
|
|
86
|
+
for (const row of rows) if (!row.counterparty.aggregate && !isUnconfirmed(row) && matchesSupplyOptions(row, options)) companies.add(row.counterparty.id);
|
|
87
|
+
locked += Math.max(0, data.counts[view][role] - rows.length);
|
|
88
|
+
}
|
|
89
|
+
return { role, counterparties: companies.size, locked };
|
|
90
|
+
}).filter((entry) => entry.counterparties > 0 || entry.locked > 0);
|
|
91
|
+
}
|
|
67
92
|
export const percentage = (row: SupplyRow) => row.pctOfRevenue === null || trustTier(row) !== 1 || isUnconfirmed(row) || !activeRelationship(row) ? "--" : `${Number(row.pctOfRevenue.toFixed(2))}% ${row.pctScope ? "scoped " : ""}${row.pctBasis ?? ""}`;
|
|
68
93
|
export const dollars = (row: SupplyRow) => row.usd === null ? "--" : `${row.usdBasis === "derived" ? "≈ " : ""}$${revenueAmount(row.usd)} ${row.usdBasis}`;
|
|
69
94
|
const scaleLabel = (scale: number) => scale === 1 ? "" : scale === 1_000 ? " thousand" : scale === 1_000_000 ? " million" : scale === 1_000_000_000 ? " billion" : ` ×${scale.toLocaleString("en-US")}`;
|