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
package/src/types/ticker.ts
CHANGED
|
@@ -56,6 +56,21 @@ export interface Portfolio {
|
|
|
56
56
|
lastSyncedAt?: number;
|
|
57
57
|
/** Set on paper portfolios shared with a team; the server holds the items. */
|
|
58
58
|
teamId?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Cash held beside the positions, entered by hand. A broker account that
|
|
61
|
+
* reports its own cash is shown instead of this.
|
|
62
|
+
*/
|
|
63
|
+
cash?: PortfolioCash;
|
|
64
|
+
/**
|
|
65
|
+
* Target weights in percent of the total value, cash included, keyed by
|
|
66
|
+
* ticker symbol; `CASH` is the cash line.
|
|
67
|
+
*/
|
|
68
|
+
targetWeights?: Record<string, number>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface PortfolioCash {
|
|
72
|
+
amount: number;
|
|
73
|
+
currency: string;
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
export interface Watchlist {
|
package/src/ui/host.tsx
CHANGED
|
@@ -461,6 +461,20 @@ export interface HostPopoverProps {
|
|
|
461
461
|
trigger: ReactNode;
|
|
462
462
|
children: ReactNode;
|
|
463
463
|
anchorPoint?: { x: number; y: number } | null;
|
|
464
|
+
/**
|
|
465
|
+
* Opens beside this element instead of the trigger, such as a name the
|
|
466
|
+
* pointer is on: below it with the left edges aligned, above it when there
|
|
467
|
+
* is no room below, and kept inside the boundary. A Box ref is one. Read
|
|
468
|
+
* each time the popover places itself, so it follows the element when the
|
|
469
|
+
* page scrolls.
|
|
470
|
+
*/
|
|
471
|
+
anchor?: BoxRenderable | null;
|
|
472
|
+
/** `pane` also keeps the popover inside the pane it opens from. Default `viewport`. */
|
|
473
|
+
boundary?: "viewport" | "pane";
|
|
474
|
+
/** The pointer came onto the popover, e.g. to keep a hover card open while it is used. */
|
|
475
|
+
onPointerEnter?: () => void;
|
|
476
|
+
/** The pointer left the popover. */
|
|
477
|
+
onPointerLeave?: () => void;
|
|
464
478
|
placement?: "bottom-start" | "bottom-end";
|
|
465
479
|
minWidth?: number | string;
|
|
466
480
|
maxWidth?: number | string;
|
package/src/updater/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { compareSemver } from "../utils/semver";
|
|
2
2
|
import { GITHUB_LATEST_RELEASE_API_URL } from "./github-releases";
|
|
3
3
|
|
|
4
|
-
function getRuntimeProcess(): Pick<NodeJS.Process, "platform" | "arch" | "argv" | "execPath"> | null {
|
|
4
|
+
function getRuntimeProcess(): Pick<NodeJS.Process, "platform" | "arch" | "argv" | "execPath" | "getBuiltinModule"> | null {
|
|
5
5
|
return (globalThis as { process?: NodeJS.Process }).process ?? null;
|
|
6
6
|
}
|
|
7
7
|
|
|
@@ -414,17 +414,15 @@ export async function performUpdate(
|
|
|
414
414
|
let unlinkUpdatePath: ((path: string) => void) | null = null;
|
|
415
415
|
|
|
416
416
|
try {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
chmodSync,
|
|
424
|
-
} = await import(fsModulePath) as typeof import("fs");
|
|
417
|
+
// Not import(): Bun folds even a specifier held in a variable and bundles
|
|
418
|
+
// browser polyfills for all three into the web and desktop view builds,
|
|
419
|
+
// which never reach this path. Self-update only runs in the compiled
|
|
420
|
+
// terminal binary, where the process is always there.
|
|
421
|
+
const runtime = getRuntimeProcess()!;
|
|
422
|
+
const { renameSync, unlinkSync, chmodSync } = runtime.getBuiltinModule("fs");
|
|
425
423
|
unlinkUpdatePath = unlinkSync;
|
|
426
|
-
const { gunzipSync } =
|
|
427
|
-
const { createHash } =
|
|
424
|
+
const { gunzipSync } = runtime.getBuiltinModule("zlib");
|
|
425
|
+
const { createHash } = runtime.getBuiltinModule("crypto");
|
|
428
426
|
|
|
429
427
|
onProgress({ phase: "downloading", percent: 0 });
|
|
430
428
|
|
|
@@ -58,3 +58,24 @@ export function abortable<T>(promise: Promise<T>, signal: AbortSignal | undefine
|
|
|
58
58
|
promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Aborts when the caller's signal does or after `timeoutMs`, whichever comes
|
|
64
|
+
* first, with that signal's reason. Wired by hand because AbortSignal.any is
|
|
65
|
+
* missing from the older system WebViews the desktop app runs in.
|
|
66
|
+
*/
|
|
67
|
+
export function signalWithTimeout(signal: AbortSignal | undefined, timeoutMs: number): AbortSignal {
|
|
68
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
69
|
+
if (!signal) return timeout;
|
|
70
|
+
if (signal.aborted) return signal;
|
|
71
|
+
const controller = new AbortController();
|
|
72
|
+
const fromCaller = () => controller.abort(signal.reason);
|
|
73
|
+
const fromTimeout = () => controller.abort(timeout.reason);
|
|
74
|
+
signal.addEventListener("abort", fromCaller, { once: true });
|
|
75
|
+
timeout.addEventListener("abort", fromTimeout, { once: true });
|
|
76
|
+
controller.signal.addEventListener("abort", () => {
|
|
77
|
+
signal.removeEventListener("abort", fromCaller);
|
|
78
|
+
timeout.removeEventListener("abort", fromTimeout);
|
|
79
|
+
}, { once: true });
|
|
80
|
+
return controller.signal;
|
|
81
|
+
}
|
package/src/utils/cli-output.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface CliTableColumn {
|
|
|
8
8
|
maxWidth?: number;
|
|
9
9
|
/** Dropped, rightmost first, before other columns are shortened to fit a terminal. */
|
|
10
10
|
optional?: boolean;
|
|
11
|
+
/** Among optional columns, a higher priority is dropped sooner; equal ones go rightmost first. */
|
|
12
|
+
dropPriority?: number;
|
|
11
13
|
/** False keeps the column whole when fitting, for identifiers a user types into the next command. */
|
|
12
14
|
shrink?: boolean;
|
|
13
15
|
}
|
|
@@ -301,7 +303,9 @@ export function renderTable(columns: CliTableColumn[], rows: string[][], options
|
|
|
301
303
|
let truncate = false;
|
|
302
304
|
if (available != null && tableWidth(shown.map((entry) => entry.width)) > available) {
|
|
303
305
|
while (tableWidth(shown.map((entry) => entry.width)) > available) {
|
|
304
|
-
const dropped = shown.
|
|
306
|
+
const dropped = shown.reduce<(typeof shown)[number] | undefined>((pick, entry) => (
|
|
307
|
+
entry.column.optional && (!pick || (entry.column.dropPriority ?? 0) >= (pick.column.dropPriority ?? 0)) ? entry : pick
|
|
308
|
+
), undefined);
|
|
305
309
|
if (!dropped) break;
|
|
306
310
|
shown = shown.filter((entry) => entry !== dropped);
|
|
307
311
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { canonicalExchange, parsePublicTickerKey } from "./exchanges";
|
|
2
|
+
|
|
3
|
+
// The fiat codes a pair against USD is read as FX for, never as a coin. The
|
|
4
|
+
// list Cloud reads: it serves these pairs by the same rule, so a copy judged
|
|
5
|
+
// here as current or stale agrees with the answer it was fetched from.
|
|
6
|
+
const FIAT_CURRENCY_CODES = new Set([
|
|
7
|
+
"USD", "EUR", "JPY", "GBP", "CHF", "CAD", "AUD", "NZD", "CNY", "CNH", "HKD", "SGD", "SEK", "NOK", "DKK",
|
|
8
|
+
"ZAR", "INR", "BRL", "MXN", "KRW", "TWD", "ILS", "PLN", "TRY", "CZK", "HUF",
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
const USD_COIN_PAIR = /^([A-Z0-9]+)[-/]USD$/;
|
|
12
|
+
|
|
13
|
+
/** A coin quoted in dollars (BTC-USD, ETH/USD). EUR-USD is spot FX, not a coin. */
|
|
14
|
+
function isUsdCoinPair(symbol: string): boolean {
|
|
15
|
+
const base = USD_COIN_PAIR.exec(symbol.trim().toUpperCase())?.[1];
|
|
16
|
+
return base !== undefined && !FIAT_CURRENCY_CODES.has(base);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A series that trades around the clock: anything on the crypto venue (CCC), or
|
|
21
|
+
* a coin quoted in dollars whether or not the caller named that venue. A bare
|
|
22
|
+
* BTC-USD is the coin, not a US listing; a bare BTC (no quote) is a US fund.
|
|
23
|
+
*/
|
|
24
|
+
export function isRoundTheClockCoin(symbol?: string, exchange?: string): boolean {
|
|
25
|
+
const parsed = symbol ? parsePublicTickerKey(symbol) : null;
|
|
26
|
+
if (canonicalExchange(parsed?.exchange ?? exchange) === "CCC" || canonicalExchange(exchange) === "CCC") return true;
|
|
27
|
+
return !!parsed && isUsdCoinPair(parsed.symbol);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// A base-quote pair such as BTC-USD or SOL-EUR. Equities with a share-class dash (BRK-B) and
|
|
31
|
+
// currency pairs (EURUSD=X) do not match.
|
|
32
|
+
const CRYPTO_PAIR = /^[A-Z0-9]{1,15}-(?:USD|EUR|GBP|USDT|USDC|BTC)$/;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Wider than isUsdCoinPair, for the hint under a pair that will not load: it
|
|
36
|
+
* also takes pairs quoted in other currencies and in coins, and does not tell
|
|
37
|
+
* a fiat base from a coin.
|
|
38
|
+
*/
|
|
39
|
+
export function isCryptoPairSymbol(symbol: string): boolean {
|
|
40
|
+
return CRYPTO_PAIR.test(symbol);
|
|
41
|
+
}
|
|
@@ -6,6 +6,20 @@ const SUB_UNIT_CURRENCIES: Record<string, { currency: string; divisor: number }>
|
|
|
6
6
|
ZAc: { currency: "ZAR", divisor: 100 },
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
+
const SUB_UNIT_NAMES: Record<string, string> = {
|
|
10
|
+
GBp: "pence",
|
|
11
|
+
GBX: "pence",
|
|
12
|
+
ILA: "agorot",
|
|
13
|
+
ZAc: "cents",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** A currency code as a reader should see it; a sub-unit says which one: "GBp (pence)". */
|
|
17
|
+
export function currencyUnitLabel(code?: string | null): string {
|
|
18
|
+
const raw = (code ?? "").trim();
|
|
19
|
+
const unit = SUB_UNIT_NAMES[raw];
|
|
20
|
+
return unit ? `${raw} (${unit})` : raw;
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
const LIKELY_UNIT_MISMATCH_RATIOS: Record<string, number[]> = {
|
|
10
24
|
BHD: [1000],
|
|
11
25
|
GBP: [100],
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// A word of its own, so a company called "ADS-TEC" is not one.
|
|
2
|
+
const DEPOSITARY_NAME = /(?:^|\s)(?:ADRs?|ADSs?|American depositary (?:receipts?|shares?))(?=$|[\s,)])/i;
|
|
3
|
+
const DEPOSITARY_TYPES = new Set(["ADR", "ADS", "DEPOSITARYRECEIPT"]);
|
|
4
|
+
/** A profile that opens by naming the security: "Toyota Motor Corporation Sponsored ADR is ...". */
|
|
5
|
+
const DEPOSITARY_SUBJECT = /^.{0,160}?\s(?:ADRs?|ADSs?|American depositary (?:receipts?|shares?)) is\s/i;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Whether a US listing is a depositary receipt, as far as its data says. A
|
|
9
|
+
* quote carries no ADR flag or ratio, so this reads the instrument type, the
|
|
10
|
+
* name, and the security name a profile description opens with. Its share
|
|
11
|
+
* count and market cap are then counted in receipts, not ordinary shares. A
|
|
12
|
+
* listing in another currency is the ordinary line even when its profile
|
|
13
|
+
* mentions the receipts.
|
|
14
|
+
*/
|
|
15
|
+
export function isDepositaryReceipt(input: {
|
|
16
|
+
instrumentType?: string | null;
|
|
17
|
+
name?: string | null;
|
|
18
|
+
currency?: string | null;
|
|
19
|
+
description?: string | null;
|
|
20
|
+
}): boolean {
|
|
21
|
+
const currency = input.currency?.trim().toUpperCase();
|
|
22
|
+
if (currency && currency !== "USD") return false;
|
|
23
|
+
if (DEPOSITARY_TYPES.has((input.instrumentType ?? "").replace(/[\s_-]/g, "").toUpperCase())) return true;
|
|
24
|
+
if (input.name && DEPOSITARY_NAME.test(input.name)) return true;
|
|
25
|
+
return DEPOSITARY_SUBJECT.test(input.description?.trim() ?? "");
|
|
26
|
+
}
|
package/src/utils/exchanges.ts
CHANGED
|
@@ -225,6 +225,78 @@ export const EXCHANGE_TIME_ZONES: Record<string, string> = {
|
|
|
225
225
|
CCC: "UTC",
|
|
226
226
|
};
|
|
227
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Venue names by canonical code, for output that names the listing a command
|
|
230
|
+
* resolved ("Euronext Paris (EPA)"). Codes whose name is the code itself
|
|
231
|
+
* (NASDAQ, BSE) are left out.
|
|
232
|
+
*/
|
|
233
|
+
const EXCHANGE_NAMES: Record<string, string> = {
|
|
234
|
+
NYSE: "New York Stock Exchange",
|
|
235
|
+
AMEX: "NYSE American",
|
|
236
|
+
ARCA: "NYSE Arca",
|
|
237
|
+
BATS: "Cboe BZX",
|
|
238
|
+
OTC: "OTC Markets",
|
|
239
|
+
JPX: "Tokyo Stock Exchange",
|
|
240
|
+
HKEX: "Hong Kong Stock Exchange",
|
|
241
|
+
LSE: "London Stock Exchange",
|
|
242
|
+
TSX: "Toronto Stock Exchange",
|
|
243
|
+
TSXV: "TSX Venture Exchange",
|
|
244
|
+
CSE: "Canadian Securities Exchange",
|
|
245
|
+
NEO: "Cboe Canada",
|
|
246
|
+
ASX: "Australian Securities Exchange",
|
|
247
|
+
CXA: "Cboe Australia",
|
|
248
|
+
NZX: "New Zealand Exchange",
|
|
249
|
+
SWX: "SIX Swiss Exchange",
|
|
250
|
+
XETRA: "Xetra",
|
|
251
|
+
FWB2: "Frankfurt Stock Exchange",
|
|
252
|
+
EPA: "Euronext Paris",
|
|
253
|
+
AMS: "Euronext Amsterdam",
|
|
254
|
+
BRU: "Euronext Brussels",
|
|
255
|
+
LIS: "Euronext Lisbon",
|
|
256
|
+
BIT: "Borsa Italiana",
|
|
257
|
+
MCE: "Bolsa de Madrid",
|
|
258
|
+
SFB: "Nasdaq Stockholm",
|
|
259
|
+
HEL: "Nasdaq Helsinki",
|
|
260
|
+
CPH: "Nasdaq Copenhagen",
|
|
261
|
+
OSL: "Euronext Oslo",
|
|
262
|
+
ICEX: "Nasdaq Iceland",
|
|
263
|
+
WSE: "Warsaw Stock Exchange",
|
|
264
|
+
PSE: "Prague Stock Exchange",
|
|
265
|
+
VIE: "Vienna Stock Exchange",
|
|
266
|
+
TWSE: "Taiwan Stock Exchange",
|
|
267
|
+
TPEX: "Taipei Exchange",
|
|
268
|
+
NSE: "National Stock Exchange of India",
|
|
269
|
+
BSE: "BSE India",
|
|
270
|
+
SSE: "Shanghai Stock Exchange",
|
|
271
|
+
SZSE: "Shenzhen Stock Exchange",
|
|
272
|
+
KRX: "Korea Exchange",
|
|
273
|
+
SGX: "Singapore Exchange",
|
|
274
|
+
BMV: "Mexican Stock Exchange",
|
|
275
|
+
BYMA: "Bolsas y Mercados Argentinos",
|
|
276
|
+
JSE: "Johannesburg Stock Exchange",
|
|
277
|
+
TASE: "Tel Aviv Stock Exchange",
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const KNOWN_EXCHANGE_CODES: ReadonlySet<string> = new Set([
|
|
281
|
+
...Object.keys(CANONICAL_EXCHANGE_ALIASES),
|
|
282
|
+
...Object.values(CANONICAL_EXCHANGE_ALIASES),
|
|
283
|
+
...Object.keys(EXCHANGE_TIME_ZONES),
|
|
284
|
+
...Object.keys(EXCHANGE_NAMES),
|
|
285
|
+
]);
|
|
286
|
+
|
|
287
|
+
/** Whether a code (any spelling the alias table takes) names a venue the app knows. */
|
|
288
|
+
export function isKnownExchangeCode(value?: string): boolean {
|
|
289
|
+
const normalized = normalizeExchange(value);
|
|
290
|
+
return !!normalized && KNOWN_EXCHANGE_CODES.has(normalized);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** "Euronext Paris (EPA)" for a venue with a name, the canonical code otherwise. */
|
|
294
|
+
export function exchangeLabel(value?: string): string {
|
|
295
|
+
const code = canonicalExchange(value);
|
|
296
|
+
const name = EXCHANGE_NAMES[code];
|
|
297
|
+
return name ? `${name} (${code})` : code;
|
|
298
|
+
}
|
|
299
|
+
|
|
228
300
|
export function normalizeSymbol(value: string): string {
|
|
229
301
|
return value.trim().toUpperCase();
|
|
230
302
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { reportCrash } from "../telemetry/crash-reports";
|
|
2
|
+
import { debugLog } from "./debug-log";
|
|
3
|
+
import { RpcTimeoutError } from "./rpc-timeout-error";
|
|
4
|
+
|
|
5
|
+
const log = debugLog.createLogger("desktop-rpc");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Starts a desktop bridge call nobody awaits without leaving its rejection
|
|
9
|
+
* unhandled. A timed-out request is logged and reported once per session
|
|
10
|
+
* (never as a crash when the machine slept, see `reportCrash`) and swallowed:
|
|
11
|
+
* the next state change sends a fresh snapshot anyway. Any other error is
|
|
12
|
+
* rethrown, so a programming error still surfaces as an unhandled rejection.
|
|
13
|
+
*
|
|
14
|
+
* `onFailure` runs for every failure, so a caller that remembers what it
|
|
15
|
+
* already sent can forget it and send again.
|
|
16
|
+
*/
|
|
17
|
+
export function fireAndForget(request: Promise<unknown> | undefined, label: string, onFailure?: () => void): void {
|
|
18
|
+
request?.catch((error: unknown) => {
|
|
19
|
+
onFailure?.();
|
|
20
|
+
if (!(error instanceof RpcTimeoutError)) throw error;
|
|
21
|
+
log.warn(`${label} did not complete: ${error.message}`);
|
|
22
|
+
reportCrash(error, { kind: "unhandled-rejection" });
|
|
23
|
+
});
|
|
24
|
+
}
|
package/src/utils/format.ts
CHANGED
|
@@ -130,6 +130,19 @@ export function formatNumber(value: number | undefined, decimals = 2): string {
|
|
|
130
130
|
return getNumberFormatter(decimals).format(value);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
/**
|
|
134
|
+
* A value to a count of significant digits, so a small ratio keeps its leading
|
|
135
|
+
* digits (0.0005664, not 0.0006) while a large one reads as a plain number
|
|
136
|
+
* (1,235). Decimals follow the rounded value, so 9.9996 reads 10.00.
|
|
137
|
+
*/
|
|
138
|
+
export function formatSignificant(value: number | undefined, digits = 4): string {
|
|
139
|
+
if (value == null || !Number.isFinite(value)) return formatNumber(undefined);
|
|
140
|
+
if (value === 0) return getNumberFormatter(0).format(0);
|
|
141
|
+
const rounded = Number(value.toPrecision(digits));
|
|
142
|
+
const decimals = Math.min(12, Math.max(0, digits - 1 - Math.floor(Math.log10(Math.abs(rounded)))));
|
|
143
|
+
return getNumberFormatter(decimals).format(rounded);
|
|
144
|
+
}
|
|
145
|
+
|
|
133
146
|
/** A percentile rank with its window: "73 pctl 1Y", "-- pctl 1Y" when unranked, "73 pctl" without a window. */
|
|
134
147
|
export function formatPercentileRank(value: number | null | undefined, window?: string): string {
|
|
135
148
|
const rank = value == null || !Number.isFinite(value) ? "--" : value.toFixed(0);
|
|
@@ -1,13 +1,80 @@
|
|
|
1
|
+
import type { Fundamentals } from "../types/financials";
|
|
1
2
|
import { formatNumber } from "./format";
|
|
2
3
|
|
|
3
4
|
export const PRICE_EARNINGS_NOTICE = "N/M = not meaningful. Non-positive P/E values are excluded from ranking.";
|
|
4
5
|
|
|
6
|
+
/** A multiple over a loss or zero base: there is no number to show, rank or export. */
|
|
7
|
+
export const NOT_MEANINGFUL = "not-meaningful";
|
|
8
|
+
export type PriceEarnings = number | typeof NOT_MEANINGFUL;
|
|
9
|
+
|
|
10
|
+
function nonPositive(value: number | null | undefined): boolean {
|
|
11
|
+
return typeof value === "number" && Number.isFinite(value) && value <= 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A P/E checked against the earnings it divides by. Zero or negative earnings
|
|
16
|
+
* make it not meaningful whatever multiple a source served beside them: a
|
|
17
|
+
* source P/E priced at an older, profitable period stays positive after the
|
|
18
|
+
* trailing EPS turns into a loss (MSTR's 5.47 beside EPS -99.08). Unknown
|
|
19
|
+
* earnings leave the multiple as served.
|
|
20
|
+
*/
|
|
21
|
+
export function priceEarningsOnEarnings(
|
|
22
|
+
multiple: number | null | undefined,
|
|
23
|
+
earnings: number | null | undefined,
|
|
24
|
+
): PriceEarnings | undefined {
|
|
25
|
+
if (nonPositive(earnings)) return NOT_MEANINGFUL;
|
|
26
|
+
return typeof multiple === "number" && Number.isFinite(multiple) ? multiple : undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
5
29
|
/** Negative earnings do not make a security cheaper than a profitable peer. */
|
|
6
|
-
export function comparablePriceEarnings(value:
|
|
7
|
-
return value
|
|
30
|
+
export function comparablePriceEarnings(value: PriceEarnings | null | undefined): number | null {
|
|
31
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
|
|
8
32
|
}
|
|
9
33
|
|
|
10
|
-
|
|
34
|
+
/** P/E, forward P/E or PEG: N/M below zero, as the multiple says nothing there. */
|
|
35
|
+
export function formatPriceEarnings(value: PriceEarnings | null | undefined, precision = 1): string {
|
|
36
|
+
if (value === NOT_MEANINGFUL) return "N/M";
|
|
11
37
|
if (value == null || !Number.isFinite(value)) return "—";
|
|
12
38
|
return value <= 0 ? "N/M" : formatNumber(value, precision);
|
|
13
39
|
}
|
|
40
|
+
|
|
41
|
+
type PriceEarningsField = "trailingPE" | "forwardPE" | "pegRatio";
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Why each earnings multiple of a fundamentals block is not meaningful, if it
|
|
45
|
+
* is not: a trailing or forward EPS at or below zero, or a multiple that is
|
|
46
|
+
* itself at or below zero. Forward P/E is judged on its own estimate only, so
|
|
47
|
+
* a trailing loss leaves a positive forward multiple alone.
|
|
48
|
+
*/
|
|
49
|
+
export function notMeaningfulMultiples(
|
|
50
|
+
fundamentals: Pick<Fundamentals, PriceEarningsField | "eps" | "forwardEps"> | undefined,
|
|
51
|
+
): Partial<Record<PriceEarningsField, string>> {
|
|
52
|
+
const reasons: Partial<Record<PriceEarningsField, string>> = {};
|
|
53
|
+
if (!fundamentals) return reasons;
|
|
54
|
+
if (nonPositive(fundamentals.eps)) reasons.trailingPE = "trailing EPS is not positive";
|
|
55
|
+
else if (nonPositive(fundamentals.trailingPE)) reasons.trailingPE = "trailing earnings are not positive";
|
|
56
|
+
if (nonPositive(fundamentals.forwardEps)) reasons.forwardPE = "forward EPS is not positive";
|
|
57
|
+
else if (nonPositive(fundamentals.forwardPE)) reasons.forwardPE = "forward earnings are not positive";
|
|
58
|
+
if (nonPositive(fundamentals.pegRatio)) reasons.pegRatio = "P/E or expected growth is not positive";
|
|
59
|
+
return reasons;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The fundamentals block as JSON exports it: a multiple that is not meaningful
|
|
64
|
+
* reads null, with the reason under `notMeaningful`, never as a number.
|
|
65
|
+
*/
|
|
66
|
+
export function exportedFundamentals<T extends Fundamentals>(
|
|
67
|
+
fundamentals: T | undefined,
|
|
68
|
+
): (Omit<T, PriceEarningsField> & Partial<Record<PriceEarningsField, number | null>> & {
|
|
69
|
+
notMeaningful?: Partial<Record<PriceEarningsField, string>>;
|
|
70
|
+
}) | undefined {
|
|
71
|
+
if (!fundamentals) return fundamentals;
|
|
72
|
+
const reasons = notMeaningfulMultiples(fundamentals);
|
|
73
|
+
const fields = Object.keys(reasons) as PriceEarningsField[];
|
|
74
|
+
if (fields.length === 0) return fundamentals;
|
|
75
|
+
return {
|
|
76
|
+
...fundamentals,
|
|
77
|
+
...Object.fromEntries(fields.map((field) => [field, null])),
|
|
78
|
+
notMeaningful: reasons,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PricePoint, TickerFinancials } from "../types/financials";
|
|
2
2
|
import { canonicalExchange, resolveExchangeTimeZone } from "./exchanges";
|
|
3
|
+
import { isRoundTheClockCoin } from "./crypto-pair";
|
|
3
4
|
import { hasPublishedSessionCalendar, isRegularSessionTime, isTimestampStaleForExchangeSession, latestRegularSessionClose, latestRegularSessionOpen, sessionCalendarTimeZone } from "../market-data/market/freshness";
|
|
4
5
|
import { zonedDateTimeParts } from "./zoned-date-time";
|
|
5
6
|
import { regularHistorySessionStaleness } from "../market-data/history-session";
|
|
@@ -10,9 +11,20 @@ const MAX_CURRENT_INTRADAY_HISTORY_LAG_MS = 18 * 60 * 60 * 1000;
|
|
|
10
11
|
const MAX_SAME_SESSION_HISTORY_LAG_MS = 30 * 60 * 1000;
|
|
11
12
|
const DELAYED_HISTORY_ALLOWANCE_MS = 15 * 60 * 1000;
|
|
12
13
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
14
|
+
// A series that never closes must reach the present without a break: no hole
|
|
15
|
+
// this long (or three bars, if larger) in the stretch before now that a
|
|
16
|
+
// current window is read over.
|
|
17
|
+
const ROUND_THE_CLOCK_RECENT_MS = 6 * 60 * 60 * 1000;
|
|
18
|
+
const ROUND_THE_CLOCK_GAP_MS = 2 * 60 * 60 * 1000;
|
|
13
19
|
|
|
14
20
|
interface PriceHistoryFreshnessOptions {
|
|
15
21
|
exchange?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The listing's symbol. A coin quoted in dollars (BTC-USD) trades around the
|
|
24
|
+
* clock whether or not the exchange says CCC; without the symbol a bare
|
|
25
|
+
* pair is read as a US listing and judged on the NYSE session.
|
|
26
|
+
*/
|
|
27
|
+
symbol?: string;
|
|
16
28
|
intervalMs?: number | null;
|
|
17
29
|
session?: HistorySession;
|
|
18
30
|
}
|
|
@@ -140,6 +152,29 @@ function normalizePriceHistoryUncached(points: PricePoint[]): PricePoint[] {
|
|
|
140
152
|
return validPoints.length === points.length ? points : validPoints;
|
|
141
153
|
}
|
|
142
154
|
|
|
155
|
+
/**
|
|
156
|
+
* A round-the-clock series is current while its latest bar is within two bars
|
|
157
|
+
* and the publishing allowance of now, with no hole in the last hours. Cloud
|
|
158
|
+
* applies the same rule to the bars it serves.
|
|
159
|
+
*/
|
|
160
|
+
function isRoundTheClockHistoryBehind(
|
|
161
|
+
points: PricePoint[], latestTime: number, now: number, intervalMs: number | null,
|
|
162
|
+
): boolean {
|
|
163
|
+
const allowedLag = intervalMs != null ? 2 * intervalMs + DELAYED_HISTORY_ALLOWANCE_MS : MAX_SAME_SESSION_HISTORY_LAG_MS;
|
|
164
|
+
if (now - latestTime > allowedLag) return true;
|
|
165
|
+
const maxGap = Math.max(3 * (intervalMs ?? 0), ROUND_THE_CLOCK_GAP_MS);
|
|
166
|
+
let later = latestTime;
|
|
167
|
+
for (let index = points.length - 1; index >= 0 && later >= now - ROUND_THE_CLOCK_RECENT_MS; index--) {
|
|
168
|
+
const point = points[index]!;
|
|
169
|
+
if (!hasFiniteClose(point)) continue;
|
|
170
|
+
const time = getPricePointTimestamp(point);
|
|
171
|
+
if (!(time < later)) continue;
|
|
172
|
+
if (later - time > maxGap) return true;
|
|
173
|
+
later = time;
|
|
174
|
+
}
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
143
178
|
export function isPriceHistoryStaleForCurrentWindow(
|
|
144
179
|
points: PricePoint[],
|
|
145
180
|
now = Date.now(),
|
|
@@ -149,7 +184,9 @@ export function isPriceHistoryStaleForCurrentWindow(
|
|
|
149
184
|
const latest = normalized.findLast(hasFiniteClose);
|
|
150
185
|
if (!latest) return false;
|
|
151
186
|
|
|
152
|
-
const
|
|
187
|
+
const coin = isRoundTheClockCoin(options.symbol, options.exchange);
|
|
188
|
+
// A coin has no session to read its bars against.
|
|
189
|
+
const session = !coin && options.session?.exchange === canonicalExchange(options.exchange)
|
|
153
190
|
? options.session : undefined;
|
|
154
191
|
const sessionInterval = session ? priceHistoryIntervalMs(session.interval) : null;
|
|
155
192
|
const intervalMs = options.intervalMs ?? sessionInterval ?? inferredHistoryIntervalMs(normalized);
|
|
@@ -159,6 +196,9 @@ export function isPriceHistoryStaleForCurrentWindow(
|
|
|
159
196
|
|
|
160
197
|
const latestTime = getPricePointTimestamp(latest);
|
|
161
198
|
if (!Number.isFinite(latestTime)) return false;
|
|
199
|
+
// Before any exchange logic: a bare BTC-USD is not a US listing, and the
|
|
200
|
+
// always-open venue's own rule lets a bar up to two hours old stand.
|
|
201
|
+
if (coin) return isRoundTheClockHistoryBehind(normalized, latestTime, now, intervalMs);
|
|
162
202
|
if (session && (options.intervalMs == null || options.intervalMs === sessionInterval)) {
|
|
163
203
|
const regularStale = regularHistorySessionStaleness(latestTime, now, session);
|
|
164
204
|
if (regularStale !== null) return regularStale;
|
|
@@ -171,15 +211,12 @@ export function isPriceHistoryStaleForCurrentWindow(
|
|
|
171
211
|
intervalMs != null ? 2 * intervalMs + DELAYED_HISTORY_ALLOWANCE_MS : 0);
|
|
172
212
|
if (age <= allowedLag) return false;
|
|
173
213
|
const exchange = options.exchange || "NASDAQ";
|
|
174
|
-
if (
|
|
175
|
-
resolveExchangeTimeZone(exchange)
|
|
176
|
-
&& isTimestampStaleForExchangeSession(latestTime, exchange, now)
|
|
177
|
-
) {
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
214
|
// Bars that reach the close of the venue's latest session stay current
|
|
181
215
|
// once it has closed, so a closed market keeps its last session until the
|
|
182
216
|
// next one opens. A copy taken earlier in that session is still behind.
|
|
217
|
+
// Asked before the quote rule below, which reads any US bar dated before
|
|
218
|
+
// today as behind from 04:00 ET: right for a last price, wrong for bars
|
|
219
|
+
// waiting for the next session's first one.
|
|
183
220
|
const regularSession = isRegularSessionTime(exchange, now);
|
|
184
221
|
if (regularSession !== null) {
|
|
185
222
|
const open = latestRegularSessionOpen(exchange, now);
|
|
@@ -190,6 +227,12 @@ export function isPriceHistoryStaleForCurrentWindow(
|
|
|
190
227
|
if (regularSession && close < open && latestTime < open && now - open <= allowedLag) return false;
|
|
191
228
|
}
|
|
192
229
|
}
|
|
230
|
+
if (
|
|
231
|
+
resolveExchangeTimeZone(exchange)
|
|
232
|
+
&& isTimestampStaleForExchangeSession(latestTime, exchange, now)
|
|
233
|
+
) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
193
236
|
const hasExchangeSession = Boolean(resolveExchangeTimeZone(exchange));
|
|
194
237
|
if (age <= MAX_CURRENT_INTRADAY_HISTORY_LAG_MS) return hasExchangeSession;
|
|
195
238
|
return !hasExchangeSession;
|
|
@@ -209,7 +252,7 @@ const BEHIND_RECHECK_BACKOFF = 4;
|
|
|
209
252
|
// re-check fails, answers nothing usable, or is rejected.
|
|
210
253
|
const UNSETTLED_RETRY_MS = 5 * 60 * 1000;
|
|
211
254
|
|
|
212
|
-
interface CalendarHistoryFetchOptions extends Pick<PriceHistoryFreshnessOptions, "exchange" | "intervalMs"> {
|
|
255
|
+
interface CalendarHistoryFetchOptions extends Pick<PriceHistoryFreshnessOptions, "exchange" | "intervalMs" | "symbol"> {
|
|
213
256
|
/**
|
|
214
257
|
* The latest check of this request, including a failed or empty one; the
|
|
215
258
|
* fetch of the copy itself when absent.
|
|
@@ -243,12 +286,13 @@ function barDate(time: number, timeZone: string): string {
|
|
|
243
286
|
* The venue date of the latest bar, read as calendarHistoryFetchState reads
|
|
244
287
|
* it, so copies whose sources label a session differently compare equal.
|
|
245
288
|
*/
|
|
246
|
-
export function calendarHistoryLastBarDate(points: PricePoint[], exchange?: string): string | null {
|
|
289
|
+
export function calendarHistoryLastBarDate(points: PricePoint[], exchange?: string, symbol?: string): string | null {
|
|
247
290
|
const latest = normalizePriceHistory(points).findLast(hasFiniteClose);
|
|
248
291
|
if (!latest) return null;
|
|
249
292
|
const time = getPricePointTimestamp(latest);
|
|
250
293
|
if (!Number.isFinite(time)) return null;
|
|
251
|
-
// Bare symbols resolve to their US listing at the sources.
|
|
294
|
+
// Bare symbols resolve to their US listing at the sources, a coin to its UTC date.
|
|
295
|
+
if (isRoundTheClockCoin(symbol, exchange)) return barDate(time, "UTC");
|
|
252
296
|
return barDate(time, sessionCalendarTimeZone(canonicalExchange(exchange) || "NYSE") ?? "UTC");
|
|
253
297
|
}
|
|
254
298
|
|
|
@@ -270,7 +314,7 @@ function isBarBeforeSession(latestTime: number, session: string, intervalMs: num
|
|
|
270
314
|
* A daily or coarser series changes at every close. A copy fetched before the
|
|
271
315
|
* latest settled close is outdated whatever its cache TTL. A copy fetched
|
|
272
316
|
* after it but without its bar is behind only where the venue's closures are
|
|
273
|
-
* published (
|
|
317
|
+
* published (hasPublishedSessionCalendar): elsewhere, and for a bare symbol whose venue is
|
|
274
318
|
* unknown, a local holiday would read as a missing session. A copy of a 24/7
|
|
275
319
|
* series goes out of date within the hour.
|
|
276
320
|
*/
|
|
@@ -285,7 +329,7 @@ export function calendarHistoryFetchState(
|
|
|
285
329
|
const intervalMs = options.intervalMs ?? inferredHistoryIntervalMs(normalized);
|
|
286
330
|
if (intervalMs == null || intervalMs < DAY_MS) return "current";
|
|
287
331
|
const exchange = canonicalExchange(options.exchange);
|
|
288
|
-
if (exchange
|
|
332
|
+
if (isRoundTheClockCoin(options.symbol, options.exchange)) {
|
|
289
333
|
return now - fetchedAt > CRYPTO_BAR_MAX_AGE_MS
|
|
290
334
|
? unsettledState(fetchedAt + CRYPTO_BAR_MAX_AGE_MS, options.checkedAt, now) : "current";
|
|
291
335
|
}
|
|
@@ -309,12 +353,13 @@ export function calendarHistoryFetchState(
|
|
|
309
353
|
export function reachesLatestSettledSession(
|
|
310
354
|
points: PricePoint[],
|
|
311
355
|
now = Date.now(),
|
|
312
|
-
options: Pick<PriceHistoryFreshnessOptions, "exchange" | "intervalMs"> = {},
|
|
356
|
+
options: Pick<PriceHistoryFreshnessOptions, "exchange" | "intervalMs" | "symbol"> = {},
|
|
313
357
|
): boolean {
|
|
314
358
|
const normalized = normalizePriceHistory(points);
|
|
315
359
|
const latest = normalized.findLast(hasFiniteClose);
|
|
316
360
|
const latestTime = latest ? getPricePointTimestamp(latest) : Number.NaN;
|
|
317
361
|
if (!Number.isFinite(latestTime)) return false;
|
|
362
|
+
if (isRoundTheClockCoin(options.symbol, options.exchange)) return false;
|
|
318
363
|
// Bare symbols resolve to their US listing at the sources.
|
|
319
364
|
const session = latestRegularSessionClose(canonicalExchange(options.exchange) || "NYSE", now - SESSION_BAR_SETTLE_MS);
|
|
320
365
|
if (!session) return false;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** A timeout this many times past its limit means the machine slept through it. */
|
|
2
|
+
const SLEEP_TIMEOUT_FACTOR = 5;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A call to the desktop's Bun process that did not complete in time: the
|
|
6
|
+
* request timer ran out, or the bridge socket never opened. `name` stays
|
|
7
|
+
* "Error", so crash reports and filters see the same type as before.
|
|
8
|
+
*/
|
|
9
|
+
export class RpcTimeoutError extends Error {
|
|
10
|
+
readonly elapsedMs: number;
|
|
11
|
+
readonly limitMs: number;
|
|
12
|
+
|
|
13
|
+
constructor(message: string, { elapsedMs, limitMs, cause }: { elapsedMs: number; limitMs: number; cause?: unknown }) {
|
|
14
|
+
super(message, cause === undefined ? undefined : { cause });
|
|
15
|
+
this.elapsedMs = elapsedMs;
|
|
16
|
+
this.limitMs = limitMs;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A timeout whose timer fired long after its limit. A laptop that sleeps
|
|
22
|
+
* suspends the page, and on wake the timer runs once for a request the Bun
|
|
23
|
+
* process already lost. Nothing the user did failed, so it is not a crash.
|
|
24
|
+
*/
|
|
25
|
+
export function isSleepRpcTimeout(error: unknown): boolean {
|
|
26
|
+
return error instanceof RpcTimeoutError && error.elapsedMs > SLEEP_TIMEOUT_FACTOR * error.limitMs;
|
|
27
|
+
}
|
package/src/utils/sec.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TickerRecord } from "../types/ticker";
|
|
2
|
-
import { canonicalExchange, US_LISTING_EXCHANGES } from "./exchanges";
|
|
2
|
+
import { canonicalExchange, parsePublicTickerKey, US_LISTING_EXCHANGES } from "./exchanges";
|
|
3
3
|
|
|
4
4
|
/** Canonical US equity venues: the listing exchanges plus other lit and OTC venues. */
|
|
5
5
|
const US_EQUITY_EXCHANGES = new Set([
|
|
@@ -102,6 +102,18 @@ export function isKnownNonUsEquityTicker(ticker: TickerRecord | null | undefined
|
|
|
102
102
|
.some((exchange) => normalize(exchange).length > 0);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* The venue an SEC issuer lookup has to respect: a listing outside the US,
|
|
107
|
+
* whose bare symbol the SEC may know as another company (SAN is Banco
|
|
108
|
+
* Santander in New York, Sanofi in Paris). Null for a US venue, a routing
|
|
109
|
+
* destination or no venue at all, which look the symbol up as a US ticker.
|
|
110
|
+
*/
|
|
111
|
+
export function nonUsSecListingVenue(ticker: string, exchange?: string): string | null {
|
|
112
|
+
const venue = parsePublicTickerKey(ticker).exchange ?? canonicalExchange(exchange);
|
|
113
|
+
if (!venue || ROUTING_EXCHANGES.has(venue) || isUsExchange(venue)) return null;
|
|
114
|
+
return venue;
|
|
115
|
+
}
|
|
116
|
+
|
|
105
117
|
/**
|
|
106
118
|
* The item codes in EDGAR's `items` field ("2.02,9.01"). EDGAR fills the same
|
|
107
119
|
* field with other values for some forms, such as the order dates of a CT
|