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
|
@@ -36,6 +36,24 @@ function cloudInternalProviderId(providerMeta?: CloudProviderMeta): string | nul
|
|
|
36
36
|
return upstream ? `${GLOOMBERB_CLOUD_PROVIDER_ID}:${upstream}` : null;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* A previous close is a price from inside the trailing 52 weeks, so it cannot
|
|
41
|
+
* sit far below the 52-week low. The service has sent 0.000205 as the
|
|
42
|
+
* Shanghai Composite's close (52-week low 3,741), which drew a +1.86e9% move.
|
|
43
|
+
* Today's price plays no part, so a real gap of any size still shows; two
|
|
44
|
+
* orders of magnitude leave room for a 52-week low that lags a crash or a split.
|
|
45
|
+
*/
|
|
46
|
+
const IMPOSSIBLE_CLOSE_FACTOR = 100;
|
|
47
|
+
|
|
48
|
+
function isImpossiblePreviousClose(
|
|
49
|
+
previousClose: number | null | undefined,
|
|
50
|
+
low52w: number | null | undefined,
|
|
51
|
+
): boolean {
|
|
52
|
+
return typeof previousClose === "number" && Number.isFinite(previousClose) && previousClose > 0
|
|
53
|
+
&& typeof low52w === "number" && Number.isFinite(low52w) && low52w > 0
|
|
54
|
+
&& previousClose * IMPOSSIBLE_CLOSE_FACTOR < low52w;
|
|
55
|
+
}
|
|
56
|
+
|
|
39
57
|
export function mapQuote(
|
|
40
58
|
quote: CloudQuotePayload,
|
|
41
59
|
providerMeta?: CloudProviderMeta,
|
|
@@ -50,10 +68,11 @@ export function mapQuote(
|
|
|
50
68
|
quote.fullExchangeName ??
|
|
51
69
|
listingExchangeName;
|
|
52
70
|
const internalProviderId = cloudInternalProviderId(providerMeta);
|
|
53
|
-
const
|
|
71
|
+
const impossibleClose = isImpossiblePreviousClose(quote.previousClose, quote.low52w);
|
|
72
|
+
const change = !impossibleClose && typeof quote.change === "number" && Number.isFinite(quote.change)
|
|
54
73
|
? quote.change / divisor
|
|
55
74
|
: Number.NaN;
|
|
56
|
-
const changePercent = typeof quote.changePercent === "number" && Number.isFinite(quote.changePercent)
|
|
75
|
+
const changePercent = !impossibleClose && typeof quote.changePercent === "number" && Number.isFinite(quote.changePercent)
|
|
57
76
|
? quote.changePercent
|
|
58
77
|
: Number.NaN;
|
|
59
78
|
// A generic future (VX1, TY1) reads in points or 32nds, not dollars.
|
|
@@ -70,8 +89,13 @@ export function mapQuote(
|
|
|
70
89
|
price: normalizePriceValueByDivisor(quote.price, divisor) ?? quote.price,
|
|
71
90
|
change,
|
|
72
91
|
changePercent,
|
|
73
|
-
previousClose: normalizePriceValueByDivisor(quote.previousClose, divisor),
|
|
92
|
+
previousClose: impossibleClose ? undefined : normalizePriceValueByDivisor(quote.previousClose, divisor),
|
|
74
93
|
regularClose: normalizePriceValueByDivisor(quote.regularClose, divisor),
|
|
94
|
+
// JSON carries an unavailable move as null; the percent is unitless.
|
|
95
|
+
regularChange: normalizePriceValueByDivisor(quote.regularChange ?? undefined, divisor),
|
|
96
|
+
regularChangePercent: typeof quote.regularChangePercent === "number" && Number.isFinite(quote.regularChangePercent)
|
|
97
|
+
? quote.regularChangePercent
|
|
98
|
+
: undefined,
|
|
75
99
|
high52w: normalizePriceValueByDivisor(quote.high52w, divisor),
|
|
76
100
|
low52w: normalizePriceValueByDivisor(quote.low52w, divisor),
|
|
77
101
|
bid: normalizePriceValueByDivisor(quote.bid, divisor),
|
|
@@ -3,6 +3,7 @@ import { CachedQuery, type CachedValue } from "../../data/cached-query";
|
|
|
3
3
|
import type { CachedAssetArgs, CachedAssetMethod, CachedAssetValue, DataProvider, MarketDataRequestContext, SecFilingItem } from "../../types/data-provider";
|
|
4
4
|
import type { AnalystResearchData, CorporateActionsData, HolderData } from "../../types/financials";
|
|
5
5
|
import { canonicalExchange } from "../../utils/exchanges";
|
|
6
|
+
import { nonUsSecListingVenue } from "../../utils/sec";
|
|
6
7
|
import { shouldLogProviderError } from "../provider-errors";
|
|
7
8
|
import { hasBrokerContext, withBrokerTimeout } from "./brokers";
|
|
8
9
|
import { publicListingExchange } from "../listing-target";
|
|
@@ -220,9 +221,11 @@ export class ProviderRouterCachedRoutes {
|
|
|
220
221
|
};
|
|
221
222
|
case "getSecFilings": {
|
|
222
223
|
const [symbol, count = 15, listingExchange, requestContext] = args as CachedAssetArgs<"getSecFilings">;
|
|
224
|
+
const exact = buildVariantKey([["exchange", canonicalExchange(listingExchange)], ["count", count]]);
|
|
223
225
|
return {
|
|
224
226
|
kind: "sec-filings", policy: "secFilings", entityKey: this.deps.getEntityKey(symbol, requestContext?.instrument),
|
|
225
|
-
|
|
227
|
+
// A non-US listing never reads the bare symbol's filings: SAN in Paris is Sanofi, SAN at the SEC is Santander.
|
|
228
|
+
variants: nonUsSecListingVenue(symbol, listingExchange) ? [exact] : [...new Set([exact, buildVariantKey([["count", count]]), ""])],
|
|
226
229
|
request: (provider, force) => provider.getSecFilings?.(symbol, count, listingExchange, force ? { ...requestContext, cacheMode: "refresh" } : requestContext),
|
|
227
230
|
throwLastError: true, error: `No SEC filings provider available for ${symbol}`,
|
|
228
231
|
};
|
|
@@ -7,7 +7,7 @@ import { redactUnavailableFundamentals, RETRACTABLE_VALUATION_FIELDS } from "../
|
|
|
7
7
|
import { isExtendedHoursExchange, isQuoteStaleForCurrentSession } from "../../market-data/quotes/freshness";
|
|
8
8
|
import { mergeQuoteMetadata, quoteMetadataFromQuote, quoteMetadataMatchesTarget } from "../../market-data/quotes/metadata";
|
|
9
9
|
import { parsePublicTickerKey } from "../../utils/exchanges";
|
|
10
|
-
import { activeUsMarketSession, isUsPriorSessionPremarketQuote } from "../../market-data/market/freshness";
|
|
10
|
+
import { activeUsMarketSession, delayedFeedLagMs, isMiddayBreakPrint, isUsPriorSessionPremarketQuote } from "../../market-data/market/freshness";
|
|
11
11
|
import {
|
|
12
12
|
mergeQuoteContributionMaps,
|
|
13
13
|
isQuoteContributionStaleForCurrentSession,
|
|
@@ -128,15 +128,16 @@ function isActiveProviderQuoteTooOld(quote: Quote, now = Date.now()): boolean {
|
|
|
128
128
|
if (!isQuoteInActiveSession(quote, now)) return false;
|
|
129
129
|
// A prior-session close before any pre-market trade has no in-session print
|
|
130
130
|
// to age; the session-date rules bound it instead.
|
|
131
|
-
|
|
131
|
+
const exchange = quote.listingExchangeName || quote.exchangeName;
|
|
132
|
+
if (isUsPriorSessionPremarketQuote(quote.lastUpdated, exchange, quote.marketState, now)) {
|
|
132
133
|
return false;
|
|
133
134
|
}
|
|
134
135
|
if (!Number.isFinite(quote.lastUpdated)) return false;
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return
|
|
136
|
+
const delayed = quote.dataSource === "delayed";
|
|
137
|
+
const maxAge = delayed ? ACTIVE_DELAYED_PROVIDER_QUOTE_MAX_AGE_MS : ACTIVE_PROVIDER_QUOTE_MAX_AGE_MS;
|
|
138
|
+
if (now - quote.lastUpdated <= maxAge) return false;
|
|
139
|
+
// While the venue pauses at midday, the morning's last print is the current price.
|
|
140
|
+
return !isMiddayBreakPrint(quote.lastUpdated, exchange, now, delayed ? delayedFeedLagMs(exchange) : 0);
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
export function providerQuoteMatchesTarget(quote: Quote | null | undefined, symbol?: string, exchange?: string): quote is Quote {
|
|
@@ -19,6 +19,7 @@ import { subtractTimeRange } from "../../time-series/date-window";
|
|
|
19
19
|
import { clipPriceHistoryToRange } from "../../time-series/history-window";
|
|
20
20
|
import { repairIsolatedIntradayOhlcOutliers } from "../../time-series/history-quality";
|
|
21
21
|
import { canonicalExchange, parsePublicTickerKey, resolveExchangeTimeZone } from "../../utils/exchanges";
|
|
22
|
+
import { isRoundTheClockCoin } from "../../utils/crypto-pair";
|
|
22
23
|
import { zonedDateKey } from "../../utils/zoned-date-time";
|
|
23
24
|
import { resolvePriceHistoryCurrencyUnit } from "../../utils/currency-units";
|
|
24
25
|
import { calendarHistoryFetchState, calendarHistoryLastBarDate, dropLeadingPlaceholderBars, getPricePointTimestamp, hasUsablePriceHistory, preservePriceHistoryGaps, isPriceHistoryStaleForCurrentWindow, normalizePriceHistory, priceHistoryIntervalMs, type CalendarHistoryFetchState } from "../../utils/price-history";
|
|
@@ -245,9 +246,9 @@ function normalizeRequestResult(value: PriceHistoryResult, request: HistoryReque
|
|
|
245
246
|
};
|
|
246
247
|
}
|
|
247
248
|
|
|
248
|
-
function resultIsStale(value: PriceHistoryResult, exchange: string, intervalMs?: number | null): boolean {
|
|
249
|
+
function resultIsStale(value: PriceHistoryResult, symbol: string, exchange: string, intervalMs?: number | null): boolean {
|
|
249
250
|
return isPriceHistoryStaleForCurrentWindow(value.points, Date.now(), {
|
|
250
|
-
exchange, intervalMs: intervalMs ?? (value.resolution ? priceHistoryIntervalMs(value.resolution) : undefined), session: value.session,
|
|
251
|
+
symbol, exchange, intervalMs: intervalMs ?? (value.resolution ? priceHistoryIntervalMs(value.resolution) : undefined), session: value.session,
|
|
251
252
|
});
|
|
252
253
|
}
|
|
253
254
|
|
|
@@ -342,8 +343,8 @@ export class ProviderRouterHistoryRoutes {
|
|
|
342
343
|
context,
|
|
343
344
|
cachePolicyKey: intraday ? "priceHistoryIntraday" : "priceHistoryDaily",
|
|
344
345
|
missingProviderError: `No history provider available for ${ticker}`,
|
|
345
|
-
isCachedValueStale: (value) => intraday && resultIsStale(value, exchange),
|
|
346
|
-
isFetchedValueStale: (value) => intraday && resultIsStale(value, exchange),
|
|
346
|
+
isCachedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange),
|
|
347
|
+
isFetchedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange),
|
|
347
348
|
fetchBroker: async (candidate) => candidate.broker.getPriceHistory
|
|
348
349
|
? candidate.broker.getPriceHistory(
|
|
349
350
|
ticker,
|
|
@@ -399,8 +400,8 @@ export class ProviderRouterHistoryRoutes {
|
|
|
399
400
|
context,
|
|
400
401
|
cachePolicyKey: intraday ? "priceHistoryIntraday" : "priceHistoryDaily",
|
|
401
402
|
missingProviderError: `No resolution-aware history provider available for ${ticker}`,
|
|
402
|
-
isCachedValueStale: (value) => intraday && resultIsStale(value, exchange, intervalMs),
|
|
403
|
-
isFetchedValueStale: (value) => intraday && resultIsStale(value, exchange, intervalMs),
|
|
403
|
+
isCachedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange, intervalMs),
|
|
404
|
+
isFetchedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange, intervalMs),
|
|
404
405
|
fetchBroker: async (candidate) => candidate.broker.getPriceHistoryForResolution
|
|
405
406
|
? candidate.broker.getPriceHistoryForResolution(
|
|
406
407
|
ticker,
|
|
@@ -515,9 +516,9 @@ export class ProviderRouterHistoryRoutes {
|
|
|
515
516
|
context,
|
|
516
517
|
cachePolicyKey: intervalMs != null && intervalMs >= 24 * 60 * 60 * 1000 ? "priceHistoryDaily" : "priceHistoryIntraday",
|
|
517
518
|
isCachedValueStale: (value) => currentWindowAtLookup
|
|
518
|
-
&& resultIsStale(value, exchange, intervalMs),
|
|
519
|
+
&& resultIsStale(value, ticker, exchange, intervalMs),
|
|
519
520
|
isFetchedValueStale: (value) => isCurrentHistoryWindow(endDate)
|
|
520
|
-
&& resultIsStale(value, exchange, intervalMs),
|
|
521
|
+
&& resultIsStale(value, ticker, exchange, intervalMs),
|
|
521
522
|
fetchBroker: async (candidate) => candidate.broker.getDetailedPriceHistory
|
|
522
523
|
? candidate.broker.getDetailedPriceHistory(
|
|
523
524
|
ticker,
|
|
@@ -568,6 +569,7 @@ export class ProviderRouterHistoryRoutes {
|
|
|
568
569
|
const now = Date.now();
|
|
569
570
|
const fetchState = (record: { fetchedAt: number; value: PriceHistoryResult }, checkedAt?: number): CalendarHistoryFetchState => currentWindow
|
|
570
571
|
? calendarHistoryFetchState(record.value.points, record.fetchedAt, now, {
|
|
572
|
+
symbol: target.symbol,
|
|
571
573
|
exchange: target.exchange || request.target.exchange,
|
|
572
574
|
checkedAt,
|
|
573
575
|
// Bar size comes from the request: a cached weekly or monthly series
|
|
@@ -580,7 +582,7 @@ export class ProviderRouterHistoryRoutes {
|
|
|
580
582
|
const ranked = cachedRecords.filter((record) => hasUsablePriceHistory(record.value.points)).map((record) => {
|
|
581
583
|
const tier = fetchTier[fetchState(record)];
|
|
582
584
|
return { record, tier, exact: request.exactCacheVariantKeys.includes(record.variantKey),
|
|
583
|
-
lastBar: tier === 0 ? "" : calendarHistoryLastBarDate(record.value.points, target.exchange || request.target.exchange) ?? "" };
|
|
585
|
+
lastBar: tier === 0 ? "" : calendarHistoryLastBarDate(record.value.points, target.exchange || request.target.exchange, target.symbol) ?? "" };
|
|
584
586
|
});
|
|
585
587
|
// Current copies keep their listed order. Otherwise ties go to this key's
|
|
586
588
|
// own copy, then the latest fetch, rather than to row order.
|
|
@@ -657,7 +659,10 @@ export class ProviderRouterHistoryRoutes {
|
|
|
657
659
|
throw new HistoryRetentionError(candidates[0]?.retention ?? attempts.retention, { candidates, outcomes: [...attempts.outcomes.values()] });
|
|
658
660
|
}
|
|
659
661
|
if (!providerResult && request.missingProviderError && !reportedGaps.some((value) => value.points.length > 0)) {
|
|
660
|
-
|
|
662
|
+
// A source answered a coin's history but it stops short of the present: say so, not that nothing answered.
|
|
663
|
+
const behind = isRoundTheClockCoin(target.symbol, target.exchange || request.target.exchange)
|
|
664
|
+
&& [...attempts.outcomes.values()].some((outcome) => outcome.outcome === "stale");
|
|
665
|
+
throw new Error(behind ? `Latest history for ${target.symbol} is behind` : request.missingProviderError);
|
|
661
666
|
}
|
|
662
667
|
return withReportedGaps(providerResult?.value ?? { points: [], resolution: historyResolutionForInterval(request.interval) });
|
|
663
668
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { SecFilingItem } from "../types/data-provider";
|
|
2
|
+
import { ProviderMissError } from "./provider-errors";
|
|
3
|
+
|
|
4
|
+
/** Legal forms and grouping words, which say nothing about which company a name is. */
|
|
5
|
+
const COMPANY_NAME_FILLER = new Set([
|
|
6
|
+
"THE", "SA", "PLC", "LTD", "LIMITED", "CORP", "CORPORATION", "INC", "INCORPORATED", "NV", "AG", "SE",
|
|
7
|
+
"HOLDING", "HOLDINGS", "GROUP", "COMPANY", "CO",
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The first word of a company name that tells it apart, in capitals without
|
|
12
|
+
* accents: "BANCO" for "Banco Santander, S.A.", "BP" for "BP p.l.c.". Null
|
|
13
|
+
* when the name is only legal forms.
|
|
14
|
+
*/
|
|
15
|
+
function companyNameToken(name: string | null | undefined): string | null {
|
|
16
|
+
const words = (name ?? "")
|
|
17
|
+
.normalize("NFKD")
|
|
18
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
19
|
+
.toUpperCase()
|
|
20
|
+
// An initialism (S.A., N.V., p.l.c.) is one word; any other dot separates two (Amazon.com).
|
|
21
|
+
.replace(/\b(?:[A-Z]\.){2,}/g, (initialism) => initialism.replaceAll(".", ""))
|
|
22
|
+
.replace(/['\u2019]/g, "")
|
|
23
|
+
.split(/[^A-Z0-9]+/);
|
|
24
|
+
return words.find((word) => word && !COMPANY_NAME_FILLER.has(word)) ?? null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Whether two names are clearly different companies. Names that cannot be
|
|
29
|
+
* compared count as the same, so only a plain conflict hides anything.
|
|
30
|
+
*/
|
|
31
|
+
export function areDifferentCompanies(left: string | null | undefined, right: string | null | undefined): boolean {
|
|
32
|
+
const leftToken = companyNameToken(left);
|
|
33
|
+
const rightToken = companyNameToken(right);
|
|
34
|
+
return !!leftToken && !!rightToken && leftToken !== rightToken;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SecListing {
|
|
38
|
+
/** The bare symbol, such as SAN. */
|
|
39
|
+
symbol: string;
|
|
40
|
+
/** The listing's canonical venue, such as EPA. */
|
|
41
|
+
exchange: string;
|
|
42
|
+
/** The listing's company, from its own quote. */
|
|
43
|
+
name: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** "No SEC filings found for Sanofi (EPA). The SEC lists SAN as Banco Santander, S.A. (NYSE)." */
|
|
47
|
+
export function secRegistrantMismatchMessage(listing: SecListing, registrantName: string, registrantExchange?: string | null): string {
|
|
48
|
+
const registrant = registrantExchange ? `${registrantName} (${registrantExchange})` : registrantName;
|
|
49
|
+
return `No SEC filings found for ${listing.name} (${listing.exchange}). The SEC lists ${listing.symbol} as ${registrant}${registrant.endsWith(".") ? "" : "."}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The SEC knows the listing's symbol as another company: SAN on EPA is Sanofi, SAN at the SEC is Banco Santander. */
|
|
53
|
+
export class SecRegistrantMismatchError extends ProviderMissError {
|
|
54
|
+
constructor(readonly listing: SecListing, readonly registrantName: string) {
|
|
55
|
+
super(secRegistrantMismatchMessage(listing, registrantName));
|
|
56
|
+
this.name = "SecRegistrantMismatchError";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The company the filings were filed by. */
|
|
61
|
+
function registrantName(filings: readonly SecFilingItem[]): string | null {
|
|
62
|
+
return filings.map((filing) => filing.companyName?.trim()).find((name): name is string => !!name) ?? null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A lookup for a listing outside the US can answer with the US registrant of
|
|
67
|
+
* the same symbol: a backend that predates venue-aware lookups ignores the
|
|
68
|
+
* venue. Those filings are another company's, so they are refused.
|
|
69
|
+
*/
|
|
70
|
+
export function assertSecRegistrantMatches(filings: readonly SecFilingItem[], listing: SecListing): void {
|
|
71
|
+
const registrant = registrantName(filings);
|
|
72
|
+
if (registrant && areDifferentCompanies(listing.name, registrant)) {
|
|
73
|
+
throw new SecRegistrantMismatchError(listing, registrant);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
import type { AppAction, AppState } from "../../../core/state/app/state";
|
|
45
45
|
import { scheduleConfigSave } from "../../config-save-scheduler";
|
|
46
46
|
import { LOW_PRIORITY_CONFIG_SAVE_DEBOUNCE_MS } from "../../persist-scheduler";
|
|
47
|
+
import { fireAndForget } from "../../../utils/fire-and-forget";
|
|
47
48
|
|
|
48
49
|
export {
|
|
49
50
|
appReducer,
|
|
@@ -565,10 +566,16 @@ export function AppProvider({
|
|
|
565
566
|
if (signature === lastMainSyncRef.current) return;
|
|
566
567
|
lastMainSyncRef.current = signature;
|
|
567
568
|
latestMainStateRevisionRef.current += 1;
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
569
|
+
// A snapshot that did not arrive must not count as sent. Forget it, unless
|
|
570
|
+
// a newer one has replaced it, so the next effect run sends it again. The
|
|
571
|
+
// two syncs below dedupe the same way.
|
|
572
|
+
fireAndForget(
|
|
573
|
+
desktopBridge.syncMainState({ ...snapshot, mainStateRevision: latestMainStateRevisionRef.current }),
|
|
574
|
+
"desktop.syncMainState",
|
|
575
|
+
() => {
|
|
576
|
+
if (lastMainSyncRef.current === signature) lastMainSyncRef.current = null;
|
|
577
|
+
},
|
|
578
|
+
);
|
|
572
579
|
}, [
|
|
573
580
|
buildDesktopSnapshot,
|
|
574
581
|
desktopBridge,
|
|
@@ -581,9 +588,12 @@ export function AppProvider({
|
|
|
581
588
|
|
|
582
589
|
useEffect(() => {
|
|
583
590
|
if (desktopBridge?.kind !== "main" || !desktopBridge.syncThemePreview) return;
|
|
584
|
-
|
|
585
|
-
lastThemePreviewSyncRef.current
|
|
586
|
-
|
|
591
|
+
const theme = state.themePreview;
|
|
592
|
+
if (lastThemePreviewSyncRef.current === theme) return;
|
|
593
|
+
lastThemePreviewSyncRef.current = theme;
|
|
594
|
+
fireAndForget(desktopBridge.syncThemePreview({ theme }), "desktop.setThemePreview", () => {
|
|
595
|
+
if (lastThemePreviewSyncRef.current === theme) lastThemePreviewSyncRef.current = undefined;
|
|
596
|
+
});
|
|
587
597
|
}, [desktopBridge, state.themePreview]);
|
|
588
598
|
|
|
589
599
|
useEffect(() => {
|
|
@@ -598,7 +608,13 @@ export function AppProvider({
|
|
|
598
608
|
const paneSignature = serializePaneState(state.paneState[desktopBridge.paneId]);
|
|
599
609
|
if (paneSignature === lastDetachedPaneSyncRef.current) return;
|
|
600
610
|
lastDetachedPaneSyncRef.current = paneSignature;
|
|
601
|
-
|
|
611
|
+
fireAndForget(
|
|
612
|
+
desktopBridge.replaceDetachedPaneState(desktopBridge.paneId, state.paneState[desktopBridge.paneId] ?? {}),
|
|
613
|
+
"desktop.replaceDetachedPaneState",
|
|
614
|
+
() => {
|
|
615
|
+
if (lastDetachedPaneSyncRef.current === paneSignature) lastDetachedPaneSyncRef.current = null;
|
|
616
|
+
},
|
|
617
|
+
);
|
|
602
618
|
}, [desktopBridge, serializePaneState, state.paneState]);
|
|
603
619
|
|
|
604
620
|
useLayoutEffect(() => {
|
|
@@ -106,21 +106,28 @@ export function useQuoteStreaming(
|
|
|
106
106
|
const paneInView = usePaneInView();
|
|
107
107
|
const coordinator = getSharedMarketDataCoordinator();
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
.sort()
|
|
122
|
-
.
|
|
123
|
-
|
|
109
|
+
// Keyed on the array, not its contents: callers memoize their targets, and a
|
|
110
|
+
// portfolio re-renders on every data frame, where re-keying and sorting a
|
|
111
|
+
// thousand targets cost a few milliseconds each time.
|
|
112
|
+
const { coordinatorTargets, identityKey, subscriptionKey } = useMemo(() => {
|
|
113
|
+
const normalizedEntries = new Map<string, QuoteSubscriptionTarget>();
|
|
114
|
+
for (const target of targets) {
|
|
115
|
+
const resolved = normalizeQuoteStreamSubscriptionTarget(target);
|
|
116
|
+
if (!resolved) continue;
|
|
117
|
+
const normalized = paneInView ? resolved : downgradeOffscreenQuoteTarget(resolved);
|
|
118
|
+
const key = buildQuoteStreamSubscriptionKey(normalized);
|
|
119
|
+
normalizedEntries.set(key, normalized);
|
|
120
|
+
}
|
|
121
|
+
const sortedEntries = [...normalizedEntries.entries()].sort(([left], [right]) => left.localeCompare(right));
|
|
122
|
+
const normalizedTargets = sortedEntries.map(([, target]) => target);
|
|
123
|
+
return {
|
|
124
|
+
coordinatorTargets: toCoordinatorQuoteTargets(normalizedTargets),
|
|
125
|
+
identityKey: [...new Set(normalizedTargets.map(buildQuoteStreamSubscriptionIdentityKey))]
|
|
126
|
+
.sort()
|
|
127
|
+
.join("\u001f"),
|
|
128
|
+
subscriptionKey: sortedEntries.map(([key]) => key).join("|"),
|
|
129
|
+
};
|
|
130
|
+
}, [paneInView, targets]);
|
|
124
131
|
const latestSubscriptionRef = useRef({
|
|
125
132
|
identityKey,
|
|
126
133
|
subscriptionKey,
|
|
@@ -208,11 +215,16 @@ export function useQuoteUpdates(
|
|
|
208
215
|
): void {
|
|
209
216
|
const appActive = useAppVisible();
|
|
210
217
|
const coordinator = getSharedMarketDataCoordinator();
|
|
211
|
-
const normalizedTargets =
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
218
|
+
const { instrumentKey, normalizedTargets } = useMemo(() => {
|
|
219
|
+
const normalized = normalizeQuoteStreamSubscriptionTargets(targets);
|
|
220
|
+
return {
|
|
221
|
+
instrumentKey: normalized
|
|
222
|
+
.map((target) => buildQuoteKey(instrumentFromQuoteTarget(target)))
|
|
223
|
+
.sort()
|
|
224
|
+
.join("\u001f"),
|
|
225
|
+
normalizedTargets: normalized,
|
|
226
|
+
};
|
|
227
|
+
}, [targets]);
|
|
216
228
|
const instruments = useMemo(() => uniqueQuoteInstruments(normalizedTargets), [instrumentKey]);
|
|
217
229
|
|
|
218
230
|
useQuoteStreaming(targets, { enabled: liveStreaming });
|
|
@@ -270,12 +282,15 @@ export function useLiveQuoteEntries(
|
|
|
270
282
|
subscriptionStartedAt: number;
|
|
271
283
|
} {
|
|
272
284
|
const appActive = useAppVisible();
|
|
273
|
-
const normalizedTargets =
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
285
|
+
const { normalizedTargets, targetKey } = useMemo(() => {
|
|
286
|
+
const normalized = normalizeQuoteStreamSubscriptionTargets(targets);
|
|
287
|
+
return {
|
|
288
|
+
normalizedTargets: normalized,
|
|
289
|
+
targetKey: [...new Set(normalized.map((target) => buildQuoteStreamSubscriptionIdentityKey(target)))]
|
|
290
|
+
.sort()
|
|
291
|
+
.join("\u001f"),
|
|
292
|
+
};
|
|
293
|
+
}, [targets]);
|
|
279
294
|
const liveStreaming = options.liveStreaming !== false;
|
|
280
295
|
const freshnessKey = options.freshnessScopeKey ?? targetKey;
|
|
281
296
|
const subscriptionKey = `${appActive ? "active" : "inactive"}\u001f${liveStreaming ? "live" : "poll"}\u001f${freshnessKey}`;
|
|
@@ -102,6 +102,10 @@ function sanitizePortfolio(portfolio: Portfolio): Portfolio {
|
|
|
102
102
|
currency: portfolio.currency,
|
|
103
103
|
brokerId: portfolio.brokerId,
|
|
104
104
|
lastSyncedAt: portfolio.lastSyncedAt,
|
|
105
|
+
// Cash and targets are the user's own entries: a pulled portfolio without
|
|
106
|
+
// them would erase them on this device.
|
|
107
|
+
...(portfolio.cash ? { cash: { ...portfolio.cash } } : {}),
|
|
108
|
+
...(portfolio.targetWeights ? { targetWeights: { ...portfolio.targetWeights } } : {}),
|
|
105
109
|
};
|
|
106
110
|
}
|
|
107
111
|
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type CrashReportsPayload,
|
|
7
7
|
} from "../api-client";
|
|
8
8
|
import type { TelemetryConfig } from "../types/config";
|
|
9
|
+
import { isSleepRpcTimeout } from "../utils/rpc-timeout-error";
|
|
9
10
|
import { VERSION } from "../version";
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -172,10 +173,12 @@ function toReportError(error: unknown, context: CrashReportContext): PendingErro
|
|
|
172
173
|
/**
|
|
173
174
|
* Queues one error. Safe to call from any error handler: it never throws,
|
|
174
175
|
* never awaits, and drops the error when reporting is off, already seen this
|
|
175
|
-
* session, or over the session cap.
|
|
176
|
+
* session, or over the session cap. A desktop request timeout that fired
|
|
177
|
+
* after the machine slept is not an error at all and is dropped too.
|
|
176
178
|
*/
|
|
177
179
|
export function reportCrash(error: unknown, context: CrashReportContext): void {
|
|
178
180
|
try {
|
|
181
|
+
if (isSleepRpcTimeout(error)) return;
|
|
179
182
|
if (host && !host.isEnabled()) return;
|
|
180
183
|
if (accepted >= MAX_ERRORS_PER_SESSION) return;
|
|
181
184
|
const entry = toReportError(error, context);
|
|
@@ -8,7 +8,8 @@ export interface PrintedCliResult {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* A command context whose `initMarketData`
|
|
11
|
+
* A command context whose `initMarketData` and `initConfigData` resolve to `market` (config, store, dataProvider, ...),
|
|
12
|
+
* with an empty ticker store unless `market` brings one.
|
|
12
13
|
* `fail` throws, every printResult call is kept in `printed`, and `closeCount` reports how many
|
|
13
14
|
* times the command closed its persistence.
|
|
14
15
|
*/
|
|
@@ -18,9 +19,16 @@ export function createTestCliContext(
|
|
|
18
19
|
): { context: CliCommandContext; printed: PrintedCliResult[]; closeCount: () => number } {
|
|
19
20
|
const printed: PrintedCliResult[] = [];
|
|
20
21
|
let closed = 0;
|
|
22
|
+
const init = async () => ({
|
|
23
|
+
persistence: { close: () => { closed += 1; } },
|
|
24
|
+
// Commands look up the saved listing of every symbol they are given.
|
|
25
|
+
store: { loadTicker: async () => null, loadAllTickers: async () => [] },
|
|
26
|
+
...market,
|
|
27
|
+
});
|
|
21
28
|
const context = {
|
|
22
29
|
cliOptions: { ...DEFAULT_CLI_OPTIONS, ...cliOptions },
|
|
23
|
-
initMarketData:
|
|
30
|
+
initMarketData: init,
|
|
31
|
+
initConfigData: init,
|
|
24
32
|
printResult: (result: CliResult<any>, options?: CliResultRenderOptions<any, any>) => { printed.push({ result, options }); },
|
|
25
33
|
fail: (message: string): never => { throw new Error(message); },
|
|
26
34
|
} as unknown as CliCommandContext;
|