gloomberb 0.16.1 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +26 -8
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +2 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +37 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +2 -0
- package/src/brokers/account-cache.ts +24 -0
- package/src/cli/commands/command-utils.ts +8 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +414 -106
- package/src/cli/commands/overview.ts +77 -32
- package/src/cli/commands/ticker.ts +101 -43
- package/src/cli/desktop-pane-shot.ts +34 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +1 -0
- package/src/cli/helpers.ts +4 -8
- package/src/cli/index.ts +12 -2
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +20 -2
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +27 -20
- package/src/cli/pane-functions/headless.ts +39 -11
- package/src/cli/pane-functions/index.ts +15 -4
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +35 -7
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +7 -3
- package/src/cli/result.ts +41 -27
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/view.tsx +29 -10
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +11 -11
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +14 -3
- package/src/components/metric-treemap/heat-surface.tsx +43 -16
- package/src/components/metric-treemap/heat-tiles.ts +18 -0
- package/src/components/metric-treemap/layout.ts +2 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/range-track.tsx +10 -3
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +7 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/data/config/store/normalize.ts +17 -1
- package/src/i18n/es.ts +19 -1
- package/src/i18n/ja.ts +19 -1
- package/src/i18n/ko.ts +19 -1
- package/src/i18n/zh-cn.ts +19 -1
- package/src/i18n/zh-tw.ts +19 -1
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +78 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +2 -0
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/risk-client.ts +191 -66
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
- package/src/plugins/builtin/analytics/risk-model.ts +45 -17
- package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
- package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/headless.ts +139 -5
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +20 -3
- package/src/plugins/builtin/holders/report-header.ts +95 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +2 -0
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
- package/src/plugins/builtin/market-movers/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +20 -3
- package/src/plugins/builtin/members/headless.ts +5 -3
- package/src/plugins/builtin/members/model.ts +10 -2
- package/src/plugins/builtin/members/pane.tsx +13 -6
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +48 -3
- package/src/plugins/builtin/pe-band/headless.ts +25 -7
- package/src/plugins/builtin/pe-band/model.ts +92 -16
- package/src/plugins/builtin/pe-band/pane.tsx +33 -16
- package/src/plugins/builtin/perps/client.ts +50 -3
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +248 -47
- package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +67 -4
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
- package/src/plugins/builtin/world-venue-map/model.ts +7 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/loader.ts +13 -1
- package/src/plugins/registry/pane-settings.ts +1 -0
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/styles.css +6 -7
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +27 -3
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financials.ts +8 -7
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/theme/heat-colors.ts +266 -84
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +3 -0
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +20 -1
- package/src/types/ticker.ts +15 -0
- package/src/ui/host.tsx +14 -0
- package/src/updater/index.ts +9 -11
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +14 -0
- package/src/utils/depositary-receipt.ts +26 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { canonicalExchange } from "../../utils/exchanges";
|
|
2
|
+
import { futuresListingVenue } from "../../utils/futures-generic";
|
|
3
|
+
import { regularSessionCloseUtcMinute } from "./freshness";
|
|
4
|
+
|
|
5
|
+
interface SessionLeg {
|
|
6
|
+
symbol: string;
|
|
7
|
+
/** The listing's exchange; without one the close is unknown and no note is made. */
|
|
8
|
+
exchange?: string;
|
|
9
|
+
/** What the reader typed, when it differs from the symbol. */
|
|
10
|
+
label?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const MINUTES_PER_DAY = 1440;
|
|
14
|
+
/** Crypto and FX carry no regular session. */
|
|
15
|
+
const ALWAYS_OPEN_EXCHANGES = new Set(["CCC", "CCY"]);
|
|
16
|
+
|
|
17
|
+
const clock = (minute: number) => `${String(Math.floor(minute / 60) % 24).padStart(2, "0")}:${String(minute % 60).padStart(2, "0")}`;
|
|
18
|
+
|
|
19
|
+
function offsetText(minutes: number): string {
|
|
20
|
+
const hours = Math.floor(minutes / 60);
|
|
21
|
+
const rest = minutes % 60;
|
|
22
|
+
return [hours ? `${hours} h` : "", rest ? `${rest} min` : ""].filter(Boolean).join(" ");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Where a daily bar of the listing falls on its date. A venue with a listed
|
|
27
|
+
* regular close closes at that UTC time. Crypto, FX and futures carry a bar
|
|
28
|
+
* dated 00:00 UTC, which closes when the next UTC day starts. A venue with
|
|
29
|
+
* neither is unknown.
|
|
30
|
+
*/
|
|
31
|
+
function dailyBarClose(leg: SessionLeg, time: number): { minute: number; text: string } | null {
|
|
32
|
+
const label = leg.label ?? leg.symbol;
|
|
33
|
+
const minute = regularSessionCloseUtcMinute(leg.exchange, time);
|
|
34
|
+
if (minute !== null) return { minute, text: `${label} closes ${clock(minute)} UTC` };
|
|
35
|
+
const exchange = canonicalExchange(leg.exchange);
|
|
36
|
+
return exchange && (ALWAYS_OPEN_EXCHANGES.has(exchange) || futuresListingVenue(leg.symbol, exchange))
|
|
37
|
+
? { minute: MINUTES_PER_DAY, text: `${label} bar is ${clock(0)} UTC` }
|
|
38
|
+
: null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* One line for a daily pair whose two sides close at different times, such as
|
|
43
|
+
* a US equity against crypto, or null when they close together (two US
|
|
44
|
+
* equities) or a close is not known. Daily closes pair by UTC date, so a
|
|
45
|
+
* reader of a correlation or ratio should know the two prices are not taken
|
|
46
|
+
* at the same moment. `dateKey` is the date the pair is read on, which
|
|
47
|
+
* settles daylight time.
|
|
48
|
+
*/
|
|
49
|
+
export function mixedSessionCloseNote(left: SessionLeg, right: SessionLeg, dateKey?: string | null): string | null {
|
|
50
|
+
const parsed = dateKey ? Date.parse(`${dateKey}T23:59:59Z`) : Number.NaN;
|
|
51
|
+
const time = Number.isFinite(parsed) ? parsed : Date.now();
|
|
52
|
+
const a = dailyBarClose(left, time);
|
|
53
|
+
const b = dailyBarClose(right, time);
|
|
54
|
+
if (!a || !b) return null;
|
|
55
|
+
const offset = Math.abs(a.minute - b.minute);
|
|
56
|
+
return offset === 0 ? null : `${a.text}; ${b.text} (${offsetText(offset)} offset). Daily pairs are matched by date.`;
|
|
57
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { MarketState, Quote } from "../../types/financials";
|
|
2
2
|
import { blendHex, colors, priceColor, type ThemeColors } from "../../theme/colors";
|
|
3
|
+
import { isFiniteNumber } from "../../utils/guards";
|
|
4
|
+
import { quoteTradingDay } from "../quotes/day-range";
|
|
3
5
|
|
|
4
6
|
const CLOSED_CHANGE_MUTING_RATIO = 0.55;
|
|
5
7
|
const US_SESSION_TIME = new Intl.DateTimeFormat("en-US", {
|
|
@@ -20,6 +22,12 @@ export interface ActiveQuoteDisplay {
|
|
|
20
22
|
changePercent?: number;
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
export type ExtendedSession = "PRE" | "POST";
|
|
26
|
+
|
|
27
|
+
export interface ExtendedSessionDisplay extends ActiveQuoteDisplay {
|
|
28
|
+
session: ExtendedSession;
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
export function marketStateLabel(state: MarketState): string {
|
|
24
32
|
switch (state) {
|
|
25
33
|
case "PRE": return "PRE-MKT";
|
|
@@ -124,6 +132,11 @@ export function exchangeShortName(exchangeName?: string, fullExchangeName?: stri
|
|
|
124
132
|
return map[name] || name;
|
|
125
133
|
}
|
|
126
134
|
|
|
135
|
+
/**
|
|
136
|
+
* The live print against the daily reference, extended hours included: what
|
|
137
|
+
* a position is worth now and its day P&L. A headline that shows an
|
|
138
|
+
* extended-hours line beside it uses getRegularSessionDisplay instead.
|
|
139
|
+
*/
|
|
127
140
|
export function getActiveQuoteDisplay(quote: Quote | null | undefined): ActiveQuoteDisplay | null {
|
|
128
141
|
if (!quote) return null;
|
|
129
142
|
if ((quote.marketState === "PRE" || quote.marketState === "PREPRE") && quote.preMarketPrice != null) {
|
|
@@ -141,3 +154,141 @@ export function getActiveQuoteDisplay(quote: Quote | null | undefined): ActiveQu
|
|
|
141
154
|
}
|
|
142
155
|
return { price: quote.price, change: quote.change, changePercent: quote.changePercent };
|
|
143
156
|
}
|
|
157
|
+
|
|
158
|
+
function isPositive(value: number | undefined): value is number {
|
|
159
|
+
return isFiniteNumber(value) && value > 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
interface CompletedRegularSession {
|
|
163
|
+
close: number;
|
|
164
|
+
/** The close's move from the session before it, when the quote reports it with the close. */
|
|
165
|
+
reported: { change: number; changePercent: number } | null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function reportedRegularMove(quote: Quote, close: number): CompletedRegularSession["reported"] {
|
|
169
|
+
const change = quote.regularChange;
|
|
170
|
+
if (!isFiniteNumber(change)) return null;
|
|
171
|
+
const reference = close - change;
|
|
172
|
+
const changePercent = isFiniteNumber(quote.regularChangePercent)
|
|
173
|
+
? quote.regularChangePercent
|
|
174
|
+
: isPositive(reference) ? (change / reference) * 100 : null;
|
|
175
|
+
return changePercent == null ? null : { change, changePercent };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The regular session the quote's day follows, once it is over: after hours,
|
|
180
|
+
* overnight, and through a weekend or holiday until the next pre-market, and
|
|
181
|
+
* in the pre-market when the quote reports the last session's close and move,
|
|
182
|
+
* which its own previous close can no longer give once the day has rolled.
|
|
183
|
+
* Only a US listing with extended trading reports one. Without a reported
|
|
184
|
+
* close, an after-hours print less its move from the close gives it. Null in
|
|
185
|
+
* the regular session.
|
|
186
|
+
*/
|
|
187
|
+
function completedRegularSession(quote: Quote): CompletedRegularSession | null {
|
|
188
|
+
const state = quote.marketState;
|
|
189
|
+
if (state == null || state === "REGULAR") return null;
|
|
190
|
+
const close = quote.regularClose;
|
|
191
|
+
if (isPositive(close)) {
|
|
192
|
+
const closeDate = quote.regularCloseSessionDate;
|
|
193
|
+
const reported = reportedRegularMove(quote, close);
|
|
194
|
+
if (state === "PRE") {
|
|
195
|
+
// The quote's own day is today; the close must be an earlier one, with its move.
|
|
196
|
+
const today = quoteTradingDay(quote);
|
|
197
|
+
return reported && closeDate && today && closeDate < today ? { close, reported } : null;
|
|
198
|
+
}
|
|
199
|
+
if (closeDate ? closeDate === quoteTradingDay(quote) : state === "POST") return { close, reported };
|
|
200
|
+
}
|
|
201
|
+
if (state === "POST" && isFiniteNumber(quote.postMarketPrice) && isFiniteNumber(quote.postMarketChange)) {
|
|
202
|
+
const derived = quote.postMarketPrice - quote.postMarketChange;
|
|
203
|
+
if (derived > 0) return { close: derived, reported: null };
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function completedRegularClose(quote: Quote): number | null {
|
|
209
|
+
return completedRegularSession(quote)?.close ?? null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The day's headline: the regular session, which stops at its close. Once it
|
|
214
|
+
* is over, and in the pre-market while the quote carries the last session's
|
|
215
|
+
* close and move, the price is that close and the move is its own, so
|
|
216
|
+
* extended trading never moves it; the extended print is
|
|
217
|
+
* getExtendedSessionDisplay. A close without its reported move is measured
|
|
218
|
+
* against the previous close. In the pre-market without that close and move
|
|
219
|
+
* the headline is the live price against the previous close, as the
|
|
220
|
+
* pre-market line is.
|
|
221
|
+
*/
|
|
222
|
+
export function getRegularSessionDisplay(quote: Quote | null | undefined): ActiveQuoteDisplay | null {
|
|
223
|
+
if (!quote) return null;
|
|
224
|
+
const session = completedRegularSession(quote);
|
|
225
|
+
if (session == null) return { price: quote.price, change: quote.change, changePercent: quote.changePercent };
|
|
226
|
+
const { close, reported } = session;
|
|
227
|
+
if (reported) return { price: close, ...reported };
|
|
228
|
+
const reference = isPositive(quote.previousClose)
|
|
229
|
+
? quote.previousClose
|
|
230
|
+
: isFiniteNumber(quote.change) && isPositive(quote.price - quote.change) ? quote.price - quote.change : null;
|
|
231
|
+
if (reference == null) return { price: close };
|
|
232
|
+
const change = close - reference;
|
|
233
|
+
return { price: close, change, changePercent: (change / reference) * 100 };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* getRegularSessionDisplay once the regular session is over (and in the
|
|
238
|
+
* pre-market, while the quote carries the last session's close and move), null
|
|
239
|
+
* while it is open. A table row headlines this when it has a column for the
|
|
240
|
+
* extended move: the close and its move stay put, and the extended column is
|
|
241
|
+
* the only figure that follows the extended print.
|
|
242
|
+
*/
|
|
243
|
+
export function getCompletedRegularSessionDisplay(quote: Quote | null | undefined): ActiveQuoteDisplay | null {
|
|
244
|
+
return quote && completedRegularClose(quote) != null ? getRegularSessionDisplay(quote) : null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The pre-market or after-hours print, measured from the regular close before
|
|
249
|
+
* it, while the quote has one: the pre-market until the open, the after-hours
|
|
250
|
+
* session from the close, and its last print until the next pre-market. Null
|
|
251
|
+
* when there is no extended print to show.
|
|
252
|
+
*/
|
|
253
|
+
export function getExtendedSessionDisplay(quote: Quote | null | undefined): ExtendedSessionDisplay | null {
|
|
254
|
+
if (!quote) return null;
|
|
255
|
+
const state = quote.marketState;
|
|
256
|
+
if (state === "PRE" || state === "PREPRE") {
|
|
257
|
+
if (isFiniteNumber(quote.preMarketPrice)) {
|
|
258
|
+
// Against the close the headline shows, so the two cannot disagree about it.
|
|
259
|
+
const close = state === "PRE" && quote.preMarketPrice > 0 ? completedRegularClose(quote) : null;
|
|
260
|
+
if (close != null) {
|
|
261
|
+
const change = quote.preMarketPrice - close;
|
|
262
|
+
return { session: "PRE", price: quote.preMarketPrice, change, changePercent: (change / close) * 100 };
|
|
263
|
+
}
|
|
264
|
+
return { session: "PRE", price: quote.preMarketPrice, change: quote.preMarketChange, changePercent: quote.preMarketChangePercent };
|
|
265
|
+
}
|
|
266
|
+
if (state === "PRE") return null;
|
|
267
|
+
}
|
|
268
|
+
const close = completedRegularClose(quote);
|
|
269
|
+
if (close == null) {
|
|
270
|
+
return state === "POST" && isFiniteNumber(quote.postMarketPrice)
|
|
271
|
+
? { session: "POST", price: quote.postMarketPrice, change: quote.postMarketChange, changePercent: quote.postMarketChangePercent }
|
|
272
|
+
: null;
|
|
273
|
+
}
|
|
274
|
+
const price = state === "POST" ? quote.postMarketPrice ?? quote.price : quote.price;
|
|
275
|
+
// Once the session is over, a last print at the close means nothing traded after it.
|
|
276
|
+
if (!isPositive(price) || (state !== "POST" && price === close)) return null;
|
|
277
|
+
const change = price - close;
|
|
278
|
+
return { session: "POST", price, change, changePercent: (change / close) * 100 };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** The extended display only while its session is open: the pre-market or the after-hours session. */
|
|
282
|
+
function getOpenExtendedSessionDisplay(quote: Quote | null | undefined): ExtendedSessionDisplay | null {
|
|
283
|
+
return quote?.marketState === "PRE" || quote?.marketState === "POST" ? getExtendedSessionDisplay(quote) : null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* The move a board of tiles colors by: the open pre-market or after-hours
|
|
288
|
+
* session's, from the regular close, otherwise the day's regular session.
|
|
289
|
+
*/
|
|
290
|
+
export function getSessionMoveDisplay(
|
|
291
|
+
quote: Quote | null | undefined,
|
|
292
|
+
): (ActiveQuoteDisplay & { session?: ExtendedSession }) | null {
|
|
293
|
+
return getOpenExtendedSessionDisplay(quote) ?? getRegularSessionDisplay(quote);
|
|
294
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Published full-day closures (weekend dates omitted) for Asia-Pacific venues,
|
|
2
|
+
// not a holiday-rule engine. A year a venue has not published is unknown, not
|
|
3
|
+
// open: every weekday of it reads as a session. Half-day sessions (HKEX and
|
|
4
|
+
// SGX eves, ASX's 14:10 closes) are not modelled. Checked 2026-10-09:
|
|
5
|
+
// KRX, also KOSDAQ: http://open.krx.co.kr/contents/MKD/01/0110/01100305/MKD01100305.jsp
|
|
6
|
+
// TWSE, whose closures TPEx shares: https://www.twse.com.tw/en/trading/holiday.html
|
|
7
|
+
// (2027 not yet published; 12 and 13 Feb 2026 are clearing-only days without trading)
|
|
8
|
+
// HKEX: https://www.hkex.com.hk/-/media/HKEX-Market/Services/Circulars-and-Notices/Participant-and-Members-Circulars/SEHK/2025/ce_SEHK_CT_075_2025.pdf
|
|
9
|
+
// and https://www.hkex.com.hk/-/media/HKEX-Market/Services/Circulars-and-Notices/Participant-and-Members-Circulars/SEHK/2026/ce_SEHK_CT_077_2026.pdf
|
|
10
|
+
// SGX closes on Singapore's gazetted public holidays, one on a Sunday moving to the Monday:
|
|
11
|
+
// https://www.sgx.com/stock-exchange/trading and https://www.mom.gov.sg/employment-practices/public-holidays
|
|
12
|
+
// ASX: https://www.asx.com.au/markets/market-resources/trading-hours-calendar/cash-market-trading-hours/trading-calendar
|
|
13
|
+
const KRX_CLOSURES: Record<number, readonly string[]> = {
|
|
14
|
+
2026: [
|
|
15
|
+
"01-01", "02-16", "02-17", "02-18", "03-02", "05-01", "05-05", "05-25", "06-03",
|
|
16
|
+
"07-17", "08-17", "09-24", "09-25", "10-05", "10-09", "12-25", "12-31",
|
|
17
|
+
],
|
|
18
|
+
2027: [
|
|
19
|
+
"01-01", "02-08", "02-09", "03-01", "05-03", "05-05", "05-13", "07-19", "08-16",
|
|
20
|
+
"09-14", "09-15", "09-16", "10-04", "10-11", "12-27", "12-31",
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const TWSE_CLOSURES: Record<number, readonly string[]> = {
|
|
25
|
+
2026: [
|
|
26
|
+
"01-01", "02-12", "02-13", "02-16", "02-17", "02-18", "02-19", "02-20", "02-27",
|
|
27
|
+
"04-03", "04-06", "05-01", "06-19", "09-25", "09-28", "10-09", "10-26", "12-25",
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Closures by canonical venue code. */
|
|
32
|
+
export const PUBLISHED_APAC_CLOSURES: Readonly<Record<string, Record<number, readonly string[]>>> = {
|
|
33
|
+
KRX: KRX_CLOSURES,
|
|
34
|
+
KOSDAQ: KRX_CLOSURES,
|
|
35
|
+
TWSE: TWSE_CLOSURES,
|
|
36
|
+
TPEX: TWSE_CLOSURES,
|
|
37
|
+
HKEX: {
|
|
38
|
+
2026: [
|
|
39
|
+
"01-01", "02-17", "02-18", "02-19", "04-03", "04-06", "04-07", "05-01", "05-25",
|
|
40
|
+
"06-19", "07-01", "10-01", "10-19", "12-25",
|
|
41
|
+
],
|
|
42
|
+
2027: [
|
|
43
|
+
"01-01", "02-08", "02-09", "03-26", "03-29", "04-05", "05-13", "06-09", "07-01",
|
|
44
|
+
"09-16", "10-01", "10-08", "12-27",
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
SGX: {
|
|
48
|
+
2026: ["01-01", "02-17", "02-18", "04-03", "05-01", "05-27", "06-01", "08-10", "11-09", "12-25"],
|
|
49
|
+
2027: ["01-01", "02-08", "03-10", "03-26", "05-17", "05-20", "08-09", "10-28"],
|
|
50
|
+
},
|
|
51
|
+
ASX: {
|
|
52
|
+
2026: ["01-01", "01-26", "04-03", "04-06", "06-08", "12-25", "12-28"],
|
|
53
|
+
2027: ["01-01", "01-26", "03-26", "03-29", "06-14", "12-27", "12-28"],
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** True only for a published full-day closure; unpublished years are unknown, not open. */
|
|
58
|
+
export function isPublishedApacClosure(exchange: string, date: string): boolean {
|
|
59
|
+
if (!Object.hasOwn(PUBLISHED_APAC_CLOSURES, exchange)) return false;
|
|
60
|
+
return PUBLISHED_APAC_CLOSURES[exchange]![Number(date.slice(0, 4))]?.includes(date.slice(5)) ?? false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** True when the venue's closures of that year are published. */
|
|
64
|
+
export function hasPublishedApacCalendar(exchange: string, year: number): boolean {
|
|
65
|
+
return Object.hasOwn(PUBLISHED_APAC_CLOSURES, exchange) && PUBLISHED_APAC_CLOSURES[exchange]![year] !== undefined;
|
|
66
|
+
}
|
|
@@ -177,6 +177,8 @@ export function mergeQuoteContribution(
|
|
|
177
177
|
priceBasis: next.priceBasis,
|
|
178
178
|
regularClose: next.regularClose,
|
|
179
179
|
regularCloseSessionDate: next.regularClose != null ? next.regularCloseSessionDate : undefined,
|
|
180
|
+
regularChange: next.regularClose != null ? next.regularChange : undefined,
|
|
181
|
+
regularChangePercent: next.regularClose != null ? next.regularChangePercent : undefined,
|
|
180
182
|
};
|
|
181
183
|
|
|
182
184
|
if (isOtherTradingDay(current, next)) {
|
|
@@ -496,6 +496,8 @@ export function resolveCanonicalQuote(
|
|
|
496
496
|
previousClose: resolved.previousClose as Quote["previousClose"],
|
|
497
497
|
regularClose: priceProvider?.regularClose,
|
|
498
498
|
regularCloseSessionDate: priceProvider?.regularClose != null ? priceProvider.regularCloseSessionDate : undefined,
|
|
499
|
+
regularChange: priceProvider?.regularClose != null ? priceProvider.regularChange : undefined,
|
|
500
|
+
regularChangePercent: priceProvider?.regularClose != null ? priceProvider.regularChangePercent : undefined,
|
|
499
501
|
changeSessionDate: resolved.changeSessionDate as Quote["changeSessionDate"],
|
|
500
502
|
high52w: resolved.high52w as Quote["high52w"],
|
|
501
503
|
low52w: resolved.low52w as Quote["low52w"],
|
|
@@ -5,6 +5,7 @@ import { buildQuoteKey, resolveEntryData } from "../selectors";
|
|
|
5
5
|
import type { QueryEntry } from "../result-types";
|
|
6
6
|
import { resolveCurrencyUnit } from "../../utils/currency-units";
|
|
7
7
|
import { isFiniteNumber } from "../../utils/guards";
|
|
8
|
+
import { getCompletedRegularSessionDisplay, getSessionMoveDisplay, type ExtendedSession } from "../market/status";
|
|
8
9
|
|
|
9
10
|
const STREAM_FRESHNESS_MS = 2 * 60_000;
|
|
10
11
|
const STREAM_CONNECTING_GRACE_MS = 15_000;
|
|
@@ -20,6 +21,24 @@ export interface ScreenerQuoteRow {
|
|
|
20
21
|
exchange: string;
|
|
21
22
|
lastUpdated?: number;
|
|
22
23
|
previousClose?: number;
|
|
24
|
+
/** Set when the price and move are an open pre-market or after-hours session's (see `extendedSessions`). */
|
|
25
|
+
extendedSession?: ExtendedSession;
|
|
26
|
+
/** Set when the price and move are the last completed regular session's close and its move; the move, in percent. */
|
|
27
|
+
regularChangePercent?: number | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ScreenerQuoteOverlayOptions {
|
|
31
|
+
/**
|
|
32
|
+
* While a pre-market or after-hours session is open, show its price and its
|
|
33
|
+
* move from the regular close, marked with `extendedSession`; otherwise the
|
|
34
|
+
* regular session's, which stops at the close. Without it a row shows the
|
|
35
|
+
* live price against the previous close. A row that is a completed regular
|
|
36
|
+
* session's close and move (`regularChangePercent`) keeps them outside the
|
|
37
|
+
* regular session when its quote has neither an open extended print nor
|
|
38
|
+
* that session's close of its own, so its price and move never come from
|
|
39
|
+
* two different days.
|
|
40
|
+
*/
|
|
41
|
+
extendedSessions?: boolean;
|
|
23
42
|
}
|
|
24
43
|
|
|
25
44
|
export interface ScreenerQuoteFreshness {
|
|
@@ -64,12 +83,14 @@ function overlayCurrency(row: ScreenerQuoteRow, quote: Quote): string {
|
|
|
64
83
|
* entries map, but most rows' quotes did not move; returning the same row
|
|
65
84
|
* object for those lets memoized table rows skip the render.
|
|
66
85
|
*/
|
|
67
|
-
const overlayCache = new WeakMap<object, { quote: Quote; row: ScreenerQuoteRow }>();
|
|
86
|
+
const overlayCache = new WeakMap<object, { quote: Quote; extended: boolean; row: ScreenerQuoteRow }>();
|
|
68
87
|
|
|
69
88
|
export function overlayScreenerQuoteEntries<T extends ScreenerQuoteRow>(
|
|
70
89
|
rows: readonly T[],
|
|
71
90
|
entries: ReadonlyMap<string, QueryEntry<Quote>>,
|
|
91
|
+
options: ScreenerQuoteOverlayOptions = {},
|
|
72
92
|
): T[] {
|
|
93
|
+
const extended = options.extendedSessions === true;
|
|
73
94
|
return rows.map((row) => {
|
|
74
95
|
const quote = resolveEntryData(entries.get(quoteKey(row)));
|
|
75
96
|
if (!quote || !isFiniteNumber(quote.price)) return row;
|
|
@@ -81,9 +102,9 @@ export function overlayScreenerQuoteEntries<T extends ScreenerQuoteRow>(
|
|
|
81
102
|
return row;
|
|
82
103
|
}
|
|
83
104
|
const cached = overlayCache.get(row);
|
|
84
|
-
if (cached?.quote === quote) return cached.row as T;
|
|
85
|
-
const overlaid = overlayQuote(row, quote);
|
|
86
|
-
overlayCache.set(row, { quote, row: overlaid });
|
|
105
|
+
if (cached?.quote === quote && cached.extended === extended) return cached.row as T;
|
|
106
|
+
const overlaid = extended ? overlaySessionQuote(row, quote) : overlayQuote(row, quote);
|
|
107
|
+
overlayCache.set(row, { quote, extended, row: overlaid });
|
|
87
108
|
return overlaid;
|
|
88
109
|
});
|
|
89
110
|
}
|
|
@@ -101,6 +122,30 @@ function overlayQuote<T extends ScreenerQuoteRow>(row: T, quote: Quote): T {
|
|
|
101
122
|
currency: overlayCurrency(row, quote),
|
|
102
123
|
previousClose: isFiniteNumber(quote.previousClose) ? quote.previousClose : undefined,
|
|
103
124
|
lastUpdated: quote.lastUpdated,
|
|
125
|
+
// The streamed price and move are no longer the snapshot's completed session.
|
|
126
|
+
...(row.regularChangePercent !== undefined ? { regularChangePercent: null } : {}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function overlaySessionQuote<T extends ScreenerQuoteRow>(row: T, quote: Quote): T {
|
|
131
|
+
const overlaid = overlayQuote(row, quote);
|
|
132
|
+
const display = getSessionMoveDisplay(quote);
|
|
133
|
+
if (!display || !isFiniteNumber(display.price)) return overlaid;
|
|
134
|
+
if (
|
|
135
|
+
!display.session
|
|
136
|
+
&& row.regularChangePercent != null
|
|
137
|
+
&& quote.marketState != null
|
|
138
|
+
&& quote.marketState !== "REGULAR"
|
|
139
|
+
&& !getCompletedRegularSessionDisplay(quote)
|
|
140
|
+
) {
|
|
141
|
+
return { ...overlaid, price: row.price, change: row.change, changePercent: row.changePercent, regularChangePercent: row.regularChangePercent };
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
...overlaid,
|
|
145
|
+
price: display.price,
|
|
146
|
+
change: isFiniteNumber(display.change) ? display.change : null,
|
|
147
|
+
changePercent: isFiniteNumber(display.changePercent) ? display.changePercent : null,
|
|
148
|
+
extendedSession: display.session,
|
|
104
149
|
};
|
|
105
150
|
}
|
|
106
151
|
|
|
@@ -22,11 +22,13 @@ import {
|
|
|
22
22
|
ScrollBox,
|
|
23
23
|
Textarea,
|
|
24
24
|
TextAttributes,
|
|
25
|
+
useUiCapabilities,
|
|
25
26
|
type ScrollBoxRenderable,
|
|
26
27
|
type TextareaRenderable,
|
|
27
28
|
} from "../../../ui";
|
|
28
29
|
import { useDialog, type AlertContext } from "../../../ui/dialog";
|
|
29
30
|
import type { SelectControl } from "../../../components/ui/select-button";
|
|
31
|
+
import { FRAMED_TEXTAREA_DESKTOP_STYLE } from "../../../components/ui/fields";
|
|
30
32
|
import { apiClient, type AccountProfile, type CloudPricing } from "../../../api-client";
|
|
31
33
|
import { chatController } from "../chat/controller";
|
|
32
34
|
import { SignInWall } from "../cloud/auth-actions";
|
|
@@ -220,6 +222,7 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
|
|
|
220
222
|
setActiveField(ACCOUNT_TAB_FIELD_ORDER[tab][0] ?? "username");
|
|
221
223
|
}), []);
|
|
222
224
|
const syncStatus = useCloudSyncStatus();
|
|
225
|
+
const { nativePaneChrome } = useUiCapabilities();
|
|
223
226
|
const bioRef = useRef<TextareaRenderable | null>(null);
|
|
224
227
|
const portfolioSelectRef = useRef<SelectControl | null>(null);
|
|
225
228
|
const refreshedSyncRevisionRef = useRef<number | null>(null);
|
|
@@ -821,6 +824,7 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
|
|
|
821
824
|
backgroundColor={colors.panel}
|
|
822
825
|
flexGrow={1}
|
|
823
826
|
wrapText
|
|
827
|
+
{...(nativePaneChrome ? { style: FRAMED_TEXTAREA_DESKTOP_STYLE } : {})}
|
|
824
828
|
onInput={(value: string) => setDraftValue("bio", value)}
|
|
825
829
|
/>
|
|
826
830
|
</Box>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { withConfigData } from "../../../cli/scoped-context";
|
|
2
2
|
import { CLI_COMMAND_GROUPS } from "../../../cli/help";
|
|
3
3
|
import { dryRunNote } from "../../../cli/helpers";
|
|
4
|
-
import { requireArg } from "../../../cli/commands/command-utils";
|
|
4
|
+
import { requireArg, takeOption } from "../../../cli/commands/command-utils";
|
|
5
|
+
import { EXCHANGE_OPTION, requireListingArg } from "../../../cli/listing-arg";
|
|
5
6
|
import { saveConfig } from "../../../data/config/store";
|
|
6
7
|
import type { CliCommandDef } from "../../../types/plugin";
|
|
7
8
|
import { cliStyles } from "../../../utils/cli-output";
|
|
@@ -18,10 +19,14 @@ export const alertsCliCommand: CliCommandDef = {
|
|
|
18
19
|
help: {
|
|
19
20
|
group: CLI_COMMAND_GROUPS.portfolios,
|
|
20
21
|
usage: ["alerts list", "alerts add <symbol> <above|below|crosses> <price>", "alerts delete <id>", "alerts rearm <id>"],
|
|
21
|
-
|
|
22
|
+
options: [EXCHANGE_OPTION],
|
|
23
|
+
examples: ["alerts", "alerts add AAPL above 250", "alerts add SAN:EPA below 70", "alerts add BTC-USD below 60000"],
|
|
22
24
|
},
|
|
23
|
-
execute: async (
|
|
25
|
+
execute: async (rawArgs, ctx) => {
|
|
26
|
+
const args = [...rawArgs];
|
|
27
|
+
const exchange = takeOption(args, "--exchange");
|
|
24
28
|
const action = args[0] ?? "list";
|
|
29
|
+
const listing = action === "add" && args[1] ? await requireListingArg(args[1], exchange, ctx) : null;
|
|
25
30
|
await withConfigData(ctx, async (config) => {
|
|
26
31
|
const raw = config.config.pluginConfig[ALERTS_PLUGIN_ID]?.[ALERTS_KEY];
|
|
27
32
|
const alerts = deserializeAlerts(typeof raw === "string" ? raw : "[]");
|
|
@@ -56,12 +61,12 @@ export const alertsCliCommand: CliCommandDef = {
|
|
|
56
61
|
return;
|
|
57
62
|
}
|
|
58
63
|
if (action === "add") {
|
|
59
|
-
const symbol = requireArg(
|
|
64
|
+
const symbol = requireArg(listing?.key, "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>", ctx);
|
|
60
65
|
const condition = requireArg(args[2], "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>", ctx) as AlertCondition;
|
|
61
66
|
if (!["above", "below", "crosses"].includes(condition)) ctx.fail("Condition must be above, below, or crosses.");
|
|
62
67
|
const price = Number(requireArg(args[3], "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>", ctx));
|
|
63
68
|
if (!Number.isFinite(price)) ctx.fail("Alert price must be a finite number.");
|
|
64
|
-
const alert = createAlert(symbol, condition, price);
|
|
69
|
+
const alert = createAlert(symbol, condition, price, listing?.exchange);
|
|
65
70
|
await saveAlerts([...alerts, alert]);
|
|
66
71
|
ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, alert } }, {
|
|
67
72
|
text: (data) => `Added alert ${data.alert.id}: ${symbol} ${condition} ${price}.${dryRunNote(data.dryRun)}`,
|
|
@@ -33,13 +33,18 @@ export function syntheticPositionUnsupportedReason(ticker: TickerRecord, quoteCu
|
|
|
33
33
|
if (positions.some((position) => position.side === "short" || position.shares < 0)) {
|
|
34
34
|
return "Short positions: signed exposure history required";
|
|
35
35
|
}
|
|
36
|
+
const category = (ticker.metadata.assetCategory ?? "").toUpperCase();
|
|
37
|
+
// Crypto trades every day at another close, so its daily returns do not pair with the equity factor proxies.
|
|
38
|
+
if (category.startsWith("CRYPTO") || /-[A-Z]{3,4}$/.test(ticker.metadata.ticker)) {
|
|
39
|
+
return "Crypto is not covered by the equity basket";
|
|
40
|
+
}
|
|
36
41
|
// "Common Stock" is the category provider search hands a ticker added from
|
|
37
42
|
// the command bar, so a plain equity must not read as unsupported.
|
|
38
43
|
const equityCategories = new Set(["", "STK", "STOCK", "COMMON STOCK", "EQUITY", "ETF", "ETN", "FUND", "ADR", "REIT"]);
|
|
39
|
-
if (!equityCategories.has(
|
|
44
|
+
if (!equityCategories.has(category)
|
|
40
45
|
|| positions.some((position) => position.multiplier != null && position.multiplier !== 1)
|
|
41
|
-
|| /=[A-Z]
|
|
42
|
-
return "
|
|
46
|
+
|| /=[A-Z]+$|\d{6}[CP]\d{8}$/.test(ticker.metadata.ticker)) {
|
|
47
|
+
return "Asset type is not covered by the equity basket";
|
|
43
48
|
}
|
|
44
49
|
if (quoteCurrency !== "USD") return "Foreign holdings: historical FX returns required";
|
|
45
50
|
return null;
|