gloomberb 0.16.0 → 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 +44 -11
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +5 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/members.ts +26 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +41 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +9 -1
- package/src/app/global-shortcuts.ts +14 -6
- package/src/app/keybindings/actions.ts +1 -1
- package/src/app/runtime/update.ts +38 -2
- package/src/app.tsx +10 -6
- 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 +36 -22
- 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/commands/collection.ts +5 -1
- 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/root/command-items.ts +9 -2
- package/src/components/command-bar/routes/root/plugin-install.ts +2 -2
- package/src/components/command-bar/routes/root/provider-search.ts +19 -5
- package/src/components/command-bar/routes/root/runtime.ts +14 -5
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +31 -5
- package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
- package/src/components/command-bar/routing/actions.ts +2 -0
- package/src/components/command-bar/selection-runtime.ts +38 -0
- package/src/components/command-bar/surface/index.tsx +7 -2
- 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/index.ts +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/floating-pane.tsx +6 -0
- package/src/components/layout/header.tsx +24 -7
- package/src/components/layout/missing-pane.tsx +2 -2
- 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 +61 -28
- package/src/components/layout/pane/index.tsx +6 -0
- package/src/components/layout/pane/title.ts +31 -7
- package/src/components/layout/shell/drag/index.ts +6 -5
- package/src/components/layout/shell/drag/runtime.ts +3 -0
- package/src/components/layout/shell/index.tsx +6 -0
- 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 +29 -10
- package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -3
- package/src/components/layout/shell/ticker-link-menu.ts +23 -9
- package/src/components/metric-treemap/heat-surface.tsx +745 -0
- package/src/components/metric-treemap/heat-tiles.ts +228 -0
- package/src/components/metric-treemap/index.tsx +2 -0
- package/src/components/metric-treemap/layout.ts +8 -0
- package/src/components/metric-treemap/scene.ts +432 -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/pane-settings-dialog/field-dialogs.tsx +1 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/toggle-list.tsx +38 -12
- package/src/components/ui/country-flag-art.tsx +449 -0
- package/src/components/ui/country-flag.tsx +41 -0
- package/src/components/ui/data-table/types.ts +13 -0
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/icon.tsx +2 -0
- package/src/components/ui/index.ts +4 -0
- package/src/components/ui/multi-select/dialog.tsx +108 -22
- package/src/components/ui/range-track.tsx +53 -0
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +11 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/core/state/app/types.ts +10 -1
- package/src/data/config/store/normalize.ts +17 -1
- package/src/i18n/es.ts +24 -4
- package/src/i18n/ja.ts +24 -4
- package/src/i18n/ko.ts +24 -4
- package/src/i18n/zh-cn.ts +24 -4
- package/src/i18n/zh-tw.ts +24 -4
- package/src/layout/ticker-navigation.ts +28 -2
- 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 +8 -0
- package/src/market-data/quotes/freshness.ts +36 -0
- package/src/market-data/quotes/resolution.ts +24 -8
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/market-data/quotes/time.ts +16 -0
- 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 +330 -79
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +61 -49
- package/src/plugins/builtin/analytics/risk-math.ts +33 -13
- package/src/plugins/builtin/analytics/risk-model.ts +282 -64
- package/src/plugins/builtin/analytics/risk-pane.tsx +62 -30
- package/src/plugins/builtin/analytics/risk-test-data.ts +206 -0
- 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/cells.tsx +15 -12
- package/src/plugins/builtin/buildout/detail/company.tsx +3 -3
- package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
- package/src/plugins/builtin/buildout/detail/intel.tsx +6 -6
- package/src/plugins/builtin/buildout/detail/site.tsx +4 -7
- package/src/plugins/builtin/buildout/detail/ui.tsx +0 -19
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/catalysts/index.tsx +2 -2
- package/src/plugins/builtin/catalysts/pane.tsx +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/cds/index.tsx +1 -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/debt-maturities/wall-bar.tsx +14 -41
- package/src/plugins/builtin/dividend-yield/client.ts +4 -2
- 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/client.ts +2 -2
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +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/fx-matrix/direction.ts +81 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +71 -33
- package/src/plugins/builtin/fx-matrix/live-legs.ts +17 -0
- package/src/plugins/builtin/fx-matrix/pairs.ts +68 -14
- package/src/plugins/builtin/fx-matrix/settings.ts +62 -0
- 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/jobs/index.tsx +1 -0
- package/src/plugins/builtin/jobs/share-bars.tsx +5 -28
- 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 +30 -2
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +245 -81
- package/src/plugins/builtin/market-heatmap/live.ts +88 -0
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +50 -11
- package/src/plugins/builtin/market-movers/client.ts +3 -2
- package/src/plugins/builtin/market-movers/headless.ts +10 -1
- package/src/plugins/builtin/market-movers/screener.ts +18 -5
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +53 -0
- package/src/plugins/builtin/members/headless.ts +35 -0
- package/src/plugins/builtin/members/index.tsx +20 -0
- package/src/plugins/builtin/members/model.ts +68 -0
- package/src/plugins/builtin/members/pane.tsx +175 -0
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/mna/index.tsx +2 -1
- package/src/plugins/builtin/mna/pane.tsx +5 -2
- 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/index.tsx +2 -1
- 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 +74 -2
- package/src/plugins/builtin/pe-band/headless.ts +26 -8
- package/src/plugins/builtin/pe-band/model.ts +102 -22
- package/src/plugins/builtin/pe-band/pane.tsx +34 -16
- package/src/plugins/builtin/pe-band/report-dates.ts +78 -0
- package/src/plugins/builtin/perps/client.ts +66 -5
- package/src/plugins/builtin/perps/equity-identity.ts +16 -0
- package/src/plugins/builtin/perps/equity-row.tsx +6 -4
- 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/plugin-marketplace/activation.ts +19 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -2
- package/src/plugins/builtin/plugin-marketplace/store.ts +2 -0
- 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/quick-add/index.tsx +43 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +48 -5
- 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/scanner/hilo-bars.tsx +12 -70
- package/src/plugins/builtin/scanner/hilo-model.ts +0 -18
- 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/move-bar.tsx +10 -32
- 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/social-mentions/index.tsx +1 -1
- 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/index.tsx +2 -1
- 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/components.tsx +5 -60
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
- package/src/plugins/builtin/ticker-detail/pane.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +7 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +20 -4
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -2
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/vol-surface/index.tsx +1 -1
- 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/catalog-browser.ts +2 -0
- package/src/plugins/catalog-manifest.ts +1 -0
- package/src/plugins/catalog-ui.ts +3 -1
- package/src/plugins/catalog.ts +1 -1
- package/src/plugins/host-link.ts +33 -1
- package/src/plugins/installer.ts +48 -12
- package/src/plugins/loader.ts +30 -3
- package/src/plugins/manager-node.ts +15 -5
- package/src/plugins/registry/index.ts +1 -1
- package/src/plugins/registry/pane-settings.ts +26 -7
- package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/row.tsx +52 -16
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/icons.tsx +1 -0
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/box.tsx +69 -26
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/host/tabs.tsx +37 -1
- package/src/renderers/dom/styles.css +41 -7
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +11 -6
- package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +181 -87
- package/src/renderers/electrobun/bun/index.ts +73 -6
- package/src/renderers/electrobun/bun/window/remembered-frame.ts +122 -0
- package/src/renderers/electrobun/shared/protocol.ts +3 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -1
- package/src/renderers/electrobun/view/main.tsx +7 -1
- package/src/renderers/electrobun/view/renderer-window-error.ts +18 -0
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/electrobun/view/update-host.ts +45 -21
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +36 -5
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financials.ts +11 -8
- 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/benign-window-error.ts +7 -0
- package/src/telemetry/crash-reports-dom.ts +2 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/test-support/daily-nav.ts +25 -0
- package/src/theme/heat-colors.ts +357 -2
- package/src/tickers/instrument-kind.ts +34 -7
- package/src/tickers/search/asset-classes.ts +24 -9
- package/src/tickers/search/index.ts +44 -11
- package/src/tickers/search/ranking.ts +23 -3
- 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 +5 -0
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +38 -6
- package/src/types/ticker.ts +15 -0
- package/src/ui/context-menu.tsx +1 -0
- package/src/ui/host.tsx +16 -0
- package/src/updater/index.ts +38 -13
- 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/i18n/ko.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Keep finance terminology precise and translations concise for dense layouts.
|
|
4
4
|
*/
|
|
5
5
|
export const ko: Record<string, string> = {
|
|
6
|
+
"NAV · as of {date}": "NAV · {date} 기준",
|
|
6
7
|
// ── Common UI ────────────────────────────────────────────────
|
|
7
8
|
"Back": "뒤로",
|
|
8
9
|
"Done": "완료",
|
|
@@ -376,7 +377,6 @@ export const ko: Record<string, string> = {
|
|
|
376
377
|
"Price trigger alerts with notifications": "알림이 있는 목표가 알림",
|
|
377
378
|
"Create a price alert from a symbol, condition, and target price": "종목코드, 조건 및 목표가로 가격 알림 생성",
|
|
378
379
|
"Public market heatmap for the largest US stocks and ETFs.": "미국 대형주 및 ETF 시장 히트맵.",
|
|
379
|
-
"Largest US stocks and ETFs, sized by market cap or assets and colored by daily move.": "미국 대형주와 ETF를 시가총액·자산 규모 및 일일 변동률로 표시.",
|
|
380
380
|
"Top gainers, losers, most active, and trending tickers": "상승률·하락률·거래량 상위 및 인기 종목",
|
|
381
381
|
"Top gainers, losers, most active, and trending tickers.": "상승률·하락률·거래량 상위 및 인기 종목.",
|
|
382
382
|
"S&P 500 sector and industry performance via ETF proxies": "ETF 기준 S&P 500 섹터 및 산업 성과",
|
|
@@ -523,7 +523,7 @@ export const ko: Record<string, string> = {
|
|
|
523
523
|
"Quit the terminal app.": "터미널 앱을 종료합니다.",
|
|
524
524
|
"Copy the active terminal selection.": "활성 터미널 선택을 복사합니다.",
|
|
525
525
|
"Paste clipboard text into the active input.": "클립보드 텍스트를 활성 입력에 붙여넣습니다.",
|
|
526
|
-
"
|
|
526
|
+
"Restart into a downloaded app update, or retry one that failed.": "다운로드한 업데이트로 다시 시작하거나, 실패한 업데이트를 다시 시도합니다.",
|
|
527
527
|
"Close the focused pane, docked or floating.": "도킹 또는 플로팅된 포커스 패널을 닫습니다.",
|
|
528
528
|
"Close all floating panes.": "모든 플로팅 패널을 닫습니다.",
|
|
529
529
|
"Edit settings for the focused pane.": "포커스 패널 설정을 편집합니다.",
|
|
@@ -835,7 +835,22 @@ export const ko: Record<string, string> = {
|
|
|
835
835
|
"Recent users": "최근 사용자",
|
|
836
836
|
"No recent users": "최근 사용자 없음",
|
|
837
837
|
"Enter at least one @username.": "@username을 하나 이상 입력하세요.",
|
|
838
|
-
"
|
|
838
|
+
"@{username} only takes DMs from people they have written to first.": "@{username}님은 먼저 메시지를 보낸 상대의 DM만 받습니다.",
|
|
839
|
+
"@{username} does not take DMs.": "@{username}님은 DM을 받지 않습니다.",
|
|
840
|
+
"@{username} was not found.": "@{username}님을 찾을 수 없습니다.",
|
|
841
|
+
"{usernames} were not found.": "{usernames}님을 찾을 수 없습니다.",
|
|
842
|
+
"One of those users was not found.": "찾을 수 없는 사용자가 있습니다.",
|
|
843
|
+
"Someone in that group only takes DMs from people they have written to first.": "이 그룹에 먼저 메시지를 보낸 상대의 DM만 받는 사람이 있습니다.",
|
|
844
|
+
"Could not start the conversation (error {status}).": "대화를 시작할 수 없습니다 (오류 {status}).",
|
|
845
|
+
"Could not start the conversation. Check your connection and try again.": "대화를 시작할 수 없습니다. 연결을 확인하고 다시 시도하세요.",
|
|
846
|
+
"no DMs": "DM 불가",
|
|
847
|
+
"Only takes DMs from people they have written to first.": "먼저 메시지를 보낸 상대의 DM만 받습니다.",
|
|
848
|
+
"Does not take DMs.": "DM을 받지 않습니다.",
|
|
849
|
+
"Message @{username}": "@{username}님에게 메시지",
|
|
850
|
+
"Open DM with @{username}": "@{username}님과의 DM 열기",
|
|
851
|
+
"Message": "메시지",
|
|
852
|
+
"Open DM": "DM 열기",
|
|
853
|
+
"Show Profile": "프로필 보기",
|
|
839
854
|
"Starting": "시작 중",
|
|
840
855
|
"Start": "시작",
|
|
841
856
|
|
|
@@ -955,7 +970,9 @@ export const ko: Record<string, string> = {
|
|
|
955
970
|
|
|
956
971
|
// ── Main dashboard ──────────────────────────────────────────
|
|
957
972
|
"Installing update...": "업데이트 설치 중...",
|
|
958
|
-
"Update
|
|
973
|
+
"Update ready, restart to apply": "업데이트 준비 완료. 적용하려면 다시 시작하세요",
|
|
974
|
+
"Update ready": "업데이트 준비 완료",
|
|
975
|
+
"Restart": "다시 시작",
|
|
959
976
|
"Checking for updates...": "업데이트 확인 중...",
|
|
960
977
|
"Downloading v{version}: {percent}%": "v{version} 다운로드 중: {percent}%",
|
|
961
978
|
"Update failed: {error}": "업데이트 실패: {error}",
|
|
@@ -970,6 +987,9 @@ export const ko: Record<string, string> = {
|
|
|
970
987
|
"Minimize": "최소화",
|
|
971
988
|
"Maximize": "최대화",
|
|
972
989
|
"Pane unavailable.": "패널을 사용할 수 없습니다.",
|
|
990
|
+
"{title} stopped working.": "{title}이(가) 작동을 멈췄습니다.",
|
|
991
|
+
"Reload pane": "패널 다시 불러오기",
|
|
992
|
+
"Close pane": "패널 닫기",
|
|
973
993
|
"Cash & Margin": "현금·증거금",
|
|
974
994
|
"No non-zero cash balances.": "표시할 현금 잔액이 없습니다.",
|
|
975
995
|
"adding...": "추가 중...",
|
package/src/i18n/zh-cn.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* fixed-width terminal layouts stay readable.
|
|
6
6
|
*/
|
|
7
7
|
export const zhCN: Record<string, string> = {
|
|
8
|
+
"NAV · as of {date}": "NAV · 截至{date}",
|
|
8
9
|
// ── Common UI ────────────────────────────────────────────────
|
|
9
10
|
"Back": "返回",
|
|
10
11
|
"Done": "完成",
|
|
@@ -378,7 +379,6 @@ export const zhCN: Record<string, string> = {
|
|
|
378
379
|
"Price trigger alerts with notifications": "带通知的价格触发提醒",
|
|
379
380
|
"Create a price alert from a symbol, condition, and target price": "用代码、条件和目标价创建价格提醒",
|
|
380
381
|
"Public market heatmap for the largest US stocks and ETFs.": "美股大盘股与 ETF 的市场热力图。",
|
|
381
|
-
"Largest US stocks and ETFs, sized by market cap or assets and colored by daily move.": "按市值/规模定大小、按日涨跌着色的美股与 ETF。",
|
|
382
382
|
"Top gainers, losers, most active, and trending tickers": "涨幅榜、跌幅榜、成交活跃与热门股票",
|
|
383
383
|
"Top gainers, losers, most active, and trending tickers.": "涨幅榜、跌幅榜、成交活跃与热门股票。",
|
|
384
384
|
"S&P 500 sector and industry performance via ETF proxies": "以 ETF 代理呈现的标普 500 板块与行业表现",
|
|
@@ -525,7 +525,7 @@ export const zhCN: Record<string, string> = {
|
|
|
525
525
|
"Quit the terminal app.": "退出终端应用。",
|
|
526
526
|
"Copy the active terminal selection.": "复制当前终端选中内容。",
|
|
527
527
|
"Paste clipboard text into the active input.": "把剪贴板文本粘贴到当前输入框。",
|
|
528
|
-
"
|
|
528
|
+
"Restart into a downloaded app update, or retry one that failed.": "使用已下载的更新重启,或重试失败的更新。",
|
|
529
529
|
"Close the focused pane, docked or floating.": "关闭聚焦面板(停靠或浮动)。",
|
|
530
530
|
"Close all floating panes.": "关闭所有浮动面板。",
|
|
531
531
|
"Edit settings for the focused pane.": "编辑聚焦面板的设置。",
|
|
@@ -837,7 +837,22 @@ export const zhCN: Record<string, string> = {
|
|
|
837
837
|
"Recent users": "最近联系人",
|
|
838
838
|
"No recent users": "没有最近联系人",
|
|
839
839
|
"Enter at least one @username.": "至少输入一个 @用户名。",
|
|
840
|
-
"
|
|
840
|
+
"@{username} only takes DMs from people they have written to first.": "@{username} 只接收自己先联系过的人的私信。",
|
|
841
|
+
"@{username} does not take DMs.": "@{username} 不接收私信。",
|
|
842
|
+
"@{username} was not found.": "找不到 @{username}。",
|
|
843
|
+
"{usernames} were not found.": "找不到 {usernames}。",
|
|
844
|
+
"One of those users was not found.": "其中有用户不存在。",
|
|
845
|
+
"Someone in that group only takes DMs from people they have written to first.": "该群组中有人只接收自己先联系过的人的私信。",
|
|
846
|
+
"Could not start the conversation (error {status}).": "无法开始会话(错误 {status})。",
|
|
847
|
+
"Could not start the conversation. Check your connection and try again.": "无法开始会话。请检查网络连接后重试。",
|
|
848
|
+
"no DMs": "不收私信",
|
|
849
|
+
"Only takes DMs from people they have written to first.": "只接收自己先联系过的人的私信。",
|
|
850
|
+
"Does not take DMs.": "不接收私信。",
|
|
851
|
+
"Message @{username}": "私信 @{username}",
|
|
852
|
+
"Open DM with @{username}": "打开与 @{username} 的私信",
|
|
853
|
+
"Message": "发私信",
|
|
854
|
+
"Open DM": "打开私信",
|
|
855
|
+
"Show Profile": "查看资料",
|
|
841
856
|
"Starting": "正在开始",
|
|
842
857
|
"Start": "开始",
|
|
843
858
|
|
|
@@ -957,7 +972,9 @@ export const zhCN: Record<string, string> = {
|
|
|
957
972
|
|
|
958
973
|
// ── Main dashboard ──────────────────────────────────────────
|
|
959
974
|
"Installing update...": "正在安装更新...",
|
|
960
|
-
"Update
|
|
975
|
+
"Update ready, restart to apply": "更新已就绪,重启后生效",
|
|
976
|
+
"Update ready": "更新已就绪",
|
|
977
|
+
"Restart": "重启",
|
|
961
978
|
"Checking for updates...": "正在检查更新...",
|
|
962
979
|
"Downloading v{version}: {percent}%": "正在下载 v{version}:{percent}%",
|
|
963
980
|
"Update failed: {error}": "更新失败:{error}",
|
|
@@ -972,6 +989,9 @@ export const zhCN: Record<string, string> = {
|
|
|
972
989
|
"Minimize": "最小化",
|
|
973
990
|
"Maximize": "最大化",
|
|
974
991
|
"Pane unavailable.": "面板不可用。",
|
|
992
|
+
"{title} stopped working.": "{title} 已停止工作。",
|
|
993
|
+
"Reload pane": "重新加载面板",
|
|
994
|
+
"Close pane": "关闭面板",
|
|
975
995
|
"Cash & Margin": "现金与保证金",
|
|
976
996
|
"No non-zero cash balances.": "没有非零现金余额。",
|
|
977
997
|
"adding...": "添加中...",
|
package/src/i18n/zh-tw.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* fixed-width terminal layouts stay readable.
|
|
6
6
|
*/
|
|
7
7
|
export const zhTW: Record<string, string> = {
|
|
8
|
+
"NAV · as of {date}": "NAV · 截至{date}",
|
|
8
9
|
// ── Common UI ────────────────────────────────────────────────
|
|
9
10
|
"Back": "返回",
|
|
10
11
|
"Done": "完成",
|
|
@@ -378,7 +379,6 @@ export const zhTW: Record<string, string> = {
|
|
|
378
379
|
"Price trigger alerts with notifications": "透過通知的價格觸發提醒",
|
|
379
380
|
"Create a price alert from a symbol, condition, and target price": "用代號、條件和目標價建立價格提醒",
|
|
380
381
|
"Public market heatmap for the largest US stocks and ETFs.": "美股大盤股與 ETF 的市場熱力圖。",
|
|
381
|
-
"Largest US stocks and ETFs, sized by market cap or assets and colored by daily move.": "按市值/規模定大小、按日漲跌著色的美股與 ETF。",
|
|
382
382
|
"Top gainers, losers, most active, and trending tickers": "漲幅榜、跌幅榜、成交活躍與熱門股票",
|
|
383
383
|
"Top gainers, losers, most active, and trending tickers.": "漲幅榜、跌幅榜、成交活躍與熱門股票。",
|
|
384
384
|
"S&P 500 sector and industry performance via ETF proxies": "以 ETF 代表 S&P 500 類股與產業表現",
|
|
@@ -525,7 +525,7 @@ export const zhTW: Record<string, string> = {
|
|
|
525
525
|
"Quit the terminal app.": "結束終端機應用程式。",
|
|
526
526
|
"Copy the active terminal selection.": "複製目前終端機選取內容。",
|
|
527
527
|
"Paste clipboard text into the active input.": "將剪貼簿文字貼到目前的輸入欄位。",
|
|
528
|
-
"
|
|
528
|
+
"Restart into a downloaded app update, or retry one that failed.": "使用已下載的更新重新啟動,或重試失敗的更新。",
|
|
529
529
|
"Close the focused pane, docked or floating.": "關閉聚焦面板(停靠或浮動)。",
|
|
530
530
|
"Close all floating panes.": "關閉所有浮動面板。",
|
|
531
531
|
"Edit settings for the focused pane.": "編輯聚焦面板的設定。",
|
|
@@ -837,7 +837,22 @@ export const zhTW: Record<string, string> = {
|
|
|
837
837
|
"Recent users": "最近聯絡人",
|
|
838
838
|
"No recent users": "沒有最近聯絡人",
|
|
839
839
|
"Enter at least one @username.": "至少輸入一個 @username。",
|
|
840
|
-
"
|
|
840
|
+
"@{username} only takes DMs from people they have written to first.": "@{username} 只接收自己先聯絡過的人的私訊。",
|
|
841
|
+
"@{username} does not take DMs.": "@{username} 不接收私訊。",
|
|
842
|
+
"@{username} was not found.": "找不到 @{username}。",
|
|
843
|
+
"{usernames} were not found.": "找不到 {usernames}。",
|
|
844
|
+
"One of those users was not found.": "其中有使用者不存在。",
|
|
845
|
+
"Someone in that group only takes DMs from people they have written to first.": "該群組中有人只接收自己先聯絡過的人的私訊。",
|
|
846
|
+
"Could not start the conversation (error {status}).": "無法開始對話(錯誤 {status})。",
|
|
847
|
+
"Could not start the conversation. Check your connection and try again.": "無法開始對話。請檢查網路連線後再試一次。",
|
|
848
|
+
"no DMs": "不收私訊",
|
|
849
|
+
"Only takes DMs from people they have written to first.": "只接收自己先聯絡過的人的私訊。",
|
|
850
|
+
"Does not take DMs.": "不接收私訊。",
|
|
851
|
+
"Message @{username}": "私訊 @{username}",
|
|
852
|
+
"Open DM with @{username}": "開啟與 @{username} 的私訊",
|
|
853
|
+
"Message": "傳私訊",
|
|
854
|
+
"Open DM": "開啟私訊",
|
|
855
|
+
"Show Profile": "查看個人資料",
|
|
841
856
|
"Starting": "正在開始",
|
|
842
857
|
"Start": "開始",
|
|
843
858
|
|
|
@@ -957,7 +972,9 @@ export const zhTW: Record<string, string> = {
|
|
|
957
972
|
|
|
958
973
|
// ── Main dashboard ──────────────────────────────────────────
|
|
959
974
|
"Installing update...": "正在安裝更新...",
|
|
960
|
-
"Update
|
|
975
|
+
"Update ready, restart to apply": "更新已就緒,重新啟動後生效",
|
|
976
|
+
"Update ready": "更新已就緒",
|
|
977
|
+
"Restart": "重新啟動",
|
|
961
978
|
"Checking for updates...": "正在檢查更新...",
|
|
962
979
|
"Downloading v{version}: {percent}%": "正在下載 v{version}:{percent}%",
|
|
963
980
|
"Update failed: {error}": "更新失敗:{error}",
|
|
@@ -972,6 +989,9 @@ export const zhTW: Record<string, string> = {
|
|
|
972
989
|
"Minimize": "最小化",
|
|
973
990
|
"Maximize": "最大化",
|
|
974
991
|
"Pane unavailable.": "面板不可用。",
|
|
992
|
+
"{title} stopped working.": "{title} 已停止運作。",
|
|
993
|
+
"Reload pane": "重新載入面板",
|
|
994
|
+
"Close pane": "關閉面板",
|
|
975
995
|
"Cash & Margin": "現金與保證金",
|
|
976
996
|
"No non-zero cash balances.": "沒有非零的現金餘額。",
|
|
977
997
|
"adding...": "新增中...",
|
|
@@ -22,8 +22,8 @@ export function listVisibleTickerSourcePanes(
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Whether the pane menu may link this pane to
|
|
26
|
-
* never follows: its own cursor symbol would win over the binding.
|
|
25
|
+
* Whether the pane menu may link this pane to another pane's ticker (`PaneDef.tickerFollower`).
|
|
26
|
+
* A source never follows: its own cursor symbol would win over the binding.
|
|
27
27
|
*/
|
|
28
28
|
export function canFollowTickerSource(
|
|
29
29
|
instance: PaneInstanceConfig,
|
|
@@ -34,6 +34,32 @@ export function canFollowTickerSource(
|
|
|
34
34
|
return typeof def.tickerFollower === "function" ? def.tickerFollower(instance) : def.tickerFollower === true;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* A single-ticker pane other panes can follow. Lists and scanners stay sources; Ticker Research
|
|
39
|
+
* follows the same rule as any pane flagged `tickerFollower`.
|
|
40
|
+
*/
|
|
41
|
+
export function isTickerLinkPeer(
|
|
42
|
+
instance: PaneInstanceConfig,
|
|
43
|
+
panes: ReadonlyMap<string, PaneDef>,
|
|
44
|
+
): boolean {
|
|
45
|
+
return instance.paneId === TICKER_RESEARCH_PANE_ID || canFollowTickerSource(instance, panes);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** True when `fromInstanceId`'s follow chain reaches `targetInstanceId`. */
|
|
49
|
+
export function followBindingReaches(
|
|
50
|
+
layout: LayoutConfig,
|
|
51
|
+
fromInstanceId: string,
|
|
52
|
+
targetInstanceId: string,
|
|
53
|
+
seen = new Set<string>(),
|
|
54
|
+
): boolean {
|
|
55
|
+
if (seen.has(fromInstanceId)) return false;
|
|
56
|
+
seen.add(fromInstanceId);
|
|
57
|
+
const instance = findPaneInstance(layout, fromInstanceId);
|
|
58
|
+
if (instance?.binding?.kind !== "follow") return false;
|
|
59
|
+
const next = instance.binding.sourceInstanceId;
|
|
60
|
+
return next === targetInstanceId || followBindingReaches(layout, next, targetInstanceId, seen);
|
|
61
|
+
}
|
|
62
|
+
|
|
37
63
|
/** The visible Ticker Research pane that follows `sourceInstanceId`, if any. */
|
|
38
64
|
export function findTickerResearchFollower(
|
|
39
65
|
layout: LayoutConfig,
|
|
@@ -57,7 +57,7 @@ export function normalizeFreshChartData(
|
|
|
57
57
|
interval: interval ?? undefined }) ?? undefined;
|
|
58
58
|
if (
|
|
59
59
|
isIntradayChartRequest(request, history)
|
|
60
|
-
&& isPriceHistoryStaleForCurrentWindow(normalized, Date.now(), { exchange: target.exchange,
|
|
60
|
+
&& isPriceHistoryStaleForCurrentWindow(normalized, Date.now(), { symbol: target.symbol, exchange: target.exchange,
|
|
61
61
|
intervalMs: interval ? priceHistoryIntervalMs(interval) : undefined, session })
|
|
62
62
|
) {
|
|
63
63
|
return [];
|
|
@@ -113,13 +113,24 @@ export async function loadQuoteEntry({
|
|
|
113
113
|
const attempts = [createAttempt(source, startedAt, "success")];
|
|
114
114
|
return quoteStore.update(key, (current) => readyQuoteEntry(current, resolvedQuote, source, attempts, { keepNewerHeldQuote: true }));
|
|
115
115
|
} catch (error) {
|
|
116
|
-
|
|
117
|
-
const attempt = createAttempt(dataProvider.id, startedAt, EXPECTED_EMPTY.test(classified.message) ? "empty" : "fatal_error", classified.reasonCode, classified.message);
|
|
118
|
-
return quoteStore.update(key, (current) => errorEntry(current, attempt));
|
|
116
|
+
return storeQuoteFailure(quoteStore, key, dataProvider.id, startedAt, error);
|
|
119
117
|
}
|
|
120
118
|
});
|
|
121
119
|
}
|
|
122
120
|
|
|
121
|
+
function storeQuoteFailure(
|
|
122
|
+
quoteStore: QueryStore<Quote>,
|
|
123
|
+
key: string,
|
|
124
|
+
providerId: string,
|
|
125
|
+
startedAt: number,
|
|
126
|
+
error: unknown,
|
|
127
|
+
): QueryEntry<Quote> {
|
|
128
|
+
const classified = classifyError(error);
|
|
129
|
+
const status = EXPECTED_EMPTY.test(classified.message) ? "empty" : "fatal_error";
|
|
130
|
+
const attempt = createAttempt(providerId, startedAt, status, classified.reasonCode, classified.message);
|
|
131
|
+
return quoteStore.update(key, (current) => errorEntry(current, attempt));
|
|
132
|
+
}
|
|
133
|
+
|
|
123
134
|
interface LoadQuoteBatchEntriesOptions {
|
|
124
135
|
dataProvider: DataProvider;
|
|
125
136
|
instruments: InstrumentRef[];
|
|
@@ -152,14 +163,22 @@ export async function loadQuoteBatchEntries({
|
|
|
152
163
|
}
|
|
153
164
|
|
|
154
165
|
if (misses.length > 0 && dataProvider.getQuotesBatch) {
|
|
166
|
+
const startedAt = Date.now();
|
|
155
167
|
const batchResults = await dataProvider.getQuotesBatch(
|
|
156
168
|
misses.map((instrument) => quoteTargetFromInstrument(instrument)),
|
|
157
169
|
{ forceRefresh: options.forceRefresh },
|
|
158
170
|
);
|
|
159
171
|
batchResults.forEach((item, index) => {
|
|
160
172
|
const instrument = misses[index];
|
|
161
|
-
if (!instrument
|
|
173
|
+
if (!instrument) return;
|
|
162
174
|
const key = buildQuoteKey(instrument);
|
|
175
|
+
if (!item.quote) {
|
|
176
|
+
// The batch already asked for this one, one by one where the batch
|
|
177
|
+
// answer fell short, and says why it failed. Asking again here would
|
|
178
|
+
// only send the same request a second time.
|
|
179
|
+
if (item.error != null) results.set(key, storeQuoteFailure(quoteStore, key, dataProvider.id, startedAt, item.error));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
163
182
|
const quote = resolveQuote?.(instrument, item.quote) ?? item.quote;
|
|
164
183
|
const source = quote.providerId ?? dataProvider.id;
|
|
165
184
|
const attempts = [createAttempt(source, Date.now(), "success")];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { CloudMarketResponse, CloudPricePointPayload } from "../api-client/types";
|
|
2
|
+
import type { FxLeg } from "./coordinator/fx-legs";
|
|
3
|
+
|
|
4
|
+
/** USD per unit of one currency at each completed daily FX close, by date. */
|
|
5
|
+
export interface FxCloses {
|
|
6
|
+
currency: string;
|
|
7
|
+
closes: ReadonlyMap<string, number>;
|
|
8
|
+
first: string;
|
|
9
|
+
asOf: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Why a daily FX history cannot be used: no usable closes, or none in the last week. */
|
|
13
|
+
export class FxHistoryError extends Error {
|
|
14
|
+
constructor(readonly problem: "unavailable" | "stale") {
|
|
15
|
+
super(problem === "stale" ? "Daily FX history is stale" : "Daily FX history unavailable");
|
|
16
|
+
this.name = "FxHistoryError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DAY_MS = 86_400_000;
|
|
21
|
+
/** A pair's latest completed close older than this is stale; a weekend and a holiday fit well inside it. */
|
|
22
|
+
const FX_MAX_AGE_DAYS = 7;
|
|
23
|
+
|
|
24
|
+
const isDay = (value: string) => /^\d{4}-\d{2}-\d{2}$/.test(value) && Number.isFinite(Date.parse(value))
|
|
25
|
+
&& new Date(value).toISOString().slice(0, 10) === value;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Completed daily closes of the pair as USD per unit, today's still-trading
|
|
29
|
+
* bar left out. A malformed row, two different closes on one date, or more
|
|
30
|
+
* rows than asked for rejects the whole history rather than a part of it.
|
|
31
|
+
*/
|
|
32
|
+
export function dailyFxCloses(
|
|
33
|
+
response: CloudMarketResponse<CloudPricePointPayload[]>,
|
|
34
|
+
leg: FxLeg,
|
|
35
|
+
now = new Date(),
|
|
36
|
+
maxRows = 1500,
|
|
37
|
+
): FxCloses {
|
|
38
|
+
if (response.status !== "success" || !Array.isArray(response.data) || response.data.length < 2) throw new FxHistoryError("unavailable");
|
|
39
|
+
if (response.stale || response.providerMeta?.stale) throw new FxHistoryError("stale");
|
|
40
|
+
if (response.data.length > maxRows) throw new FxHistoryError("unavailable");
|
|
41
|
+
const today = now.toISOString().slice(0, 10);
|
|
42
|
+
const closes = new Map<string, number>();
|
|
43
|
+
for (const row of response.data) {
|
|
44
|
+
if (!row || typeof row.date !== "string" || !Number.isFinite(Date.parse(row.date)) || !isDay(row.date.slice(0, 10))
|
|
45
|
+
|| !Number.isFinite(row.close) || row.close <= 0) throw new FxHistoryError("unavailable");
|
|
46
|
+
const date = new Date(row.date).toISOString().slice(0, 10);
|
|
47
|
+
if (date >= today) continue;
|
|
48
|
+
const rate = leg.invert ? 1 / row.close : row.close;
|
|
49
|
+
const previous = closes.get(date);
|
|
50
|
+
if (previous != null && previous !== rate) throw new FxHistoryError("unavailable");
|
|
51
|
+
closes.set(date, rate);
|
|
52
|
+
}
|
|
53
|
+
const dates = [...closes.keys()].sort();
|
|
54
|
+
const asOf = dates.at(-1);
|
|
55
|
+
if (!asOf || Date.parse(today) - Date.parse(asOf) > FX_MAX_AGE_DAYS * DAY_MS) throw new FxHistoryError("stale");
|
|
56
|
+
return { currency: leg.currency, closes, first: dates[0]!, asOf };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The last completed close on or before `date` (YYYY-MM-DD), looking back at
|
|
61
|
+
* most a week so a weekend or holiday finds the close before it but a gap in
|
|
62
|
+
* the history is not bridged.
|
|
63
|
+
*/
|
|
64
|
+
export function fxCloseOnOrBefore(fx: FxCloses, date: string): { date: string; rate: number } | null {
|
|
65
|
+
const end = Date.parse(`${(date < fx.asOf ? date : fx.asOf)}T00:00:00Z`);
|
|
66
|
+
for (let back = 0; back <= FX_MAX_AGE_DAYS; back++) {
|
|
67
|
+
const day = new Date(end - back * DAY_MS).toISOString().slice(0, 10);
|
|
68
|
+
const rate = fx.closes.get(day);
|
|
69
|
+
if (rate != null) return { date: day, rate };
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MarketState } from "../../types/financials";
|
|
2
2
|
import { canonicalExchange, EXCHANGE_TIME_ZONES, isUsListingExchange } from "../../utils/exchanges";
|
|
3
|
+
import { hasPublishedApacCalendar, isPublishedApacClosure } from "../published-apac-sessions";
|
|
3
4
|
import { hasPublishedCnCalendar, isPublishedCnClosure } from "../published-cn-sessions";
|
|
4
5
|
import { hasPublishedJpxCalendar, isPublishedJpxClosure } from "../published-jpx-sessions";
|
|
5
6
|
import { hasPublishedNseCalendar, isPublishedNseClosure } from "../published-nse-sessions";
|
|
@@ -11,6 +12,9 @@ const ALWAYS_OPEN_EXCHANGES = new Set(["CCC"]);
|
|
|
11
12
|
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
12
13
|
const OVERNIGHT_CLOSE_MAX_AGE_MS = 20 * 60 * 60 * 1000;
|
|
13
14
|
const ALWAYS_OPEN_MAX_AGE_MS = 2 * 60 * 60 * 1000;
|
|
15
|
+
// Spring Festival can put the previous session twelve calendar days back
|
|
16
|
+
// (TWSE, February 2026).
|
|
17
|
+
const SESSION_LOOKBACK_DAYS = 14;
|
|
14
18
|
const REGULAR_OPEN_MINUTES: Record<string, number> = {
|
|
15
19
|
NASDAQ: 9 * 60 + 30,
|
|
16
20
|
NYSE: 9 * 60 + 30,
|
|
@@ -72,6 +76,28 @@ const REGULAR_CLOSE_MINUTES: Record<string, number> = {
|
|
|
72
76
|
NZX: 17 * 60, SSE: 15 * 60 + 30, SZSE: 15 * 60 + 30,
|
|
73
77
|
BMV: 15 * 60 + 10, B3: 18 * 60 + 30, BYMA: 17 * 60 + 10, JSE: 17 * 60 + 15, TASE: 17 * 60 + 40,
|
|
74
78
|
};
|
|
79
|
+
// Venues that pause at midday, as local minutes [start, end), with a zone for
|
|
80
|
+
// those the session tables above do not cover. Jakarta pauses longer on Fridays.
|
|
81
|
+
const MIDDAY_BREAKS: Record<string, {
|
|
82
|
+
timeZone?: string;
|
|
83
|
+
weekdays: readonly [number, number];
|
|
84
|
+
friday?: readonly [number, number];
|
|
85
|
+
}> = {
|
|
86
|
+
HKEX: { weekdays: [12 * 60, 13 * 60] },
|
|
87
|
+
SGX: { weekdays: [12 * 60, 13 * 60] },
|
|
88
|
+
SSE: { weekdays: [11 * 60 + 30, 13 * 60] },
|
|
89
|
+
SZSE: { weekdays: [11 * 60 + 30, 13 * 60] },
|
|
90
|
+
JPX: { weekdays: [11 * 60 + 30, 12 * 60 + 30] },
|
|
91
|
+
BURSAMY: { timeZone: "Asia/Kuala_Lumpur", weekdays: [12 * 60 + 30, 14 * 60 + 30] },
|
|
92
|
+
JAKARTA: { timeZone: "Asia/Jakarta", weekdays: [12 * 60, 13 * 60 + 30], friday: [11 * 60 + 30, 14 * 60] },
|
|
93
|
+
};
|
|
94
|
+
// A morning print this close to the break is its last one, and afternoon
|
|
95
|
+
// prints are due this long after the feed's lag has passed the reopening.
|
|
96
|
+
const MIDDAY_BREAK_MARGIN_MS = 5 * 60_000;
|
|
97
|
+
// How far the delayed feed runs behind each venue's trades.
|
|
98
|
+
const DELAYED_FEED_LAG_MS = 15 * 60_000;
|
|
99
|
+
const SLOWER_DELAYED_FEED_LAG_MS = 20 * 60_000;
|
|
100
|
+
const SLOWER_DELAYED_FEEDS = new Set(["ASX", "KRX", "KOSDAQ", "TWSE", "TPEX", "SGX", "NZX"]);
|
|
75
101
|
const exchangeLocalTimeFormatters = new Map<string, Intl.DateTimeFormat>();
|
|
76
102
|
const usSessionFormatter = new Intl.DateTimeFormat("en-US", {
|
|
77
103
|
timeZone: "America/New_York",
|
|
@@ -159,6 +185,7 @@ function isPublishedClosure(exchange: string, date: string): boolean {
|
|
|
159
185
|
if (exchange === "JPX") return isPublishedJpxClosure(date);
|
|
160
186
|
if (exchange === "NSE" || exchange === "BSE") return isPublishedNseClosure(date);
|
|
161
187
|
if (exchange === "SSE" || exchange === "SZSE") return isPublishedCnClosure(date);
|
|
188
|
+
if (isPublishedApacClosure(exchange, date)) return true;
|
|
162
189
|
return getPublishedUsEquityCalendarDay(exchange, date) === "closed";
|
|
163
190
|
}
|
|
164
191
|
|
|
@@ -207,9 +234,7 @@ export function latestRegularSessionClose(
|
|
|
207
234
|
if (!timeZone || ALWAYS_OPEN_EXCHANGES.has(canonical) || !Number.isFinite(time)) return null;
|
|
208
235
|
const { year, month, day } = zonedDateTimeParts(time, timeZone);
|
|
209
236
|
const today = Date.UTC(year, month - 1, day) / MS_PER_DAY;
|
|
210
|
-
|
|
211
|
-
const lookback = (canonical === "SSE" || canonical === "SZSE") && hasPublishedCnCalendar(year) ? 14 : 10;
|
|
212
|
-
for (let offset = 0; offset <= lookback; offset++) {
|
|
237
|
+
for (let offset = 0; offset <= SESSION_LOOKBACK_DAYS; offset++) {
|
|
213
238
|
const date = new Date((today - offset) * MS_PER_DAY).toISOString().slice(0, 10);
|
|
214
239
|
const published = getPublishedUsEquitySession(canonical, date);
|
|
215
240
|
let close: number | null = null;
|
|
@@ -225,6 +250,20 @@ export function latestRegularSessionClose(
|
|
|
225
250
|
return null;
|
|
226
251
|
}
|
|
227
252
|
|
|
253
|
+
/**
|
|
254
|
+
* The UTC minute of the day the venue's regular session closed, for the latest
|
|
255
|
+
* session at or before `time` (20:00 UTC is 1200 while New York is on daylight
|
|
256
|
+
* time). Null for round-the-clock venues and for venues whose close hour is
|
|
257
|
+
* not listed, which `latestRegularSessionClose` would take to close at local
|
|
258
|
+
* midnight.
|
|
259
|
+
*/
|
|
260
|
+
export function regularSessionCloseUtcMinute(exchange: string | undefined, time: number): number | null {
|
|
261
|
+
const canonical = canonicalExchange(exchange);
|
|
262
|
+
if (REGULAR_CLOSE_MINUTES[canonical] === undefined) return null;
|
|
263
|
+
const close = latestRegularSessionClose(canonical, time);
|
|
264
|
+
return close ? Math.floor(close.close / 60_000) % 1440 : null;
|
|
265
|
+
}
|
|
266
|
+
|
|
228
267
|
/**
|
|
229
268
|
* The open of the regular session `time` falls in, or of the latest one
|
|
230
269
|
* before it: the published calendar for US venues, otherwise the venue's
|
|
@@ -238,8 +277,7 @@ export function latestRegularSessionOpen(exchange: string | undefined, time: num
|
|
|
238
277
|
const minutes = REGULAR_OPEN_MINUTES[canonical];
|
|
239
278
|
const { year, month, day } = zonedDateTimeParts(time, timeZone);
|
|
240
279
|
const today = Date.UTC(year, month - 1, day) / MS_PER_DAY;
|
|
241
|
-
|
|
242
|
-
for (let offset = 0; offset <= lookback; offset++) {
|
|
280
|
+
for (let offset = 0; offset <= SESSION_LOOKBACK_DAYS; offset++) {
|
|
243
281
|
const date = new Date((today - offset) * MS_PER_DAY).toISOString().slice(0, 10);
|
|
244
282
|
const published = getPublishedUsEquitySession(canonical, date);
|
|
245
283
|
let open: number | null = null;
|
|
@@ -270,7 +308,8 @@ export function isRegularSessionTime(exchange: string | undefined, time: number)
|
|
|
270
308
|
|
|
271
309
|
/**
|
|
272
310
|
* True when the venue's full-day closures for the year of `date` are
|
|
273
|
-
* published: US venues, JPX, NSE, BSE, SSE
|
|
311
|
+
* published: US venues, JPX, NSE, BSE, SSE, SZSE, KRX, KOSDAQ, TWSE, TPEX,
|
|
312
|
+
* HKEX, SGX and ASX. Elsewhere a local holiday reads as a weekday.
|
|
274
313
|
*/
|
|
275
314
|
export function hasPublishedSessionCalendar(exchange: string | undefined, date: string): boolean {
|
|
276
315
|
const canonical = canonicalExchange(exchange);
|
|
@@ -278,9 +317,42 @@ export function hasPublishedSessionCalendar(exchange: string | undefined, date:
|
|
|
278
317
|
if (canonical === "JPX") return hasPublishedJpxCalendar(year);
|
|
279
318
|
if (canonical === "NSE" || canonical === "BSE") return hasPublishedNseCalendar(year);
|
|
280
319
|
if (canonical === "SSE" || canonical === "SZSE") return hasPublishedCnCalendar(year);
|
|
320
|
+
if (hasPublishedApacCalendar(canonical, year)) return true;
|
|
281
321
|
return !!getPublishedUsEquityCalendarYears(canonical)?.includes(year);
|
|
282
322
|
}
|
|
283
323
|
|
|
324
|
+
/** How far the delayed feed runs behind the venue's trades. */
|
|
325
|
+
export function delayedFeedLagMs(exchange: string | undefined): number {
|
|
326
|
+
return SLOWER_DELAYED_FEEDS.has(canonicalExchange(exchange)) ? SLOWER_DELAYED_FEED_LAG_MS : DELAYED_FEED_LAG_MS;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Whether a print is still the current price because the venue is paused at
|
|
331
|
+
* midday: `now` falls in the break, or within the feed's lag plus five
|
|
332
|
+
* minutes after it, and the print is the morning's last, no earlier than five
|
|
333
|
+
* minutes before the break started. An earlier morning print means the feed
|
|
334
|
+
* stopped before the break.
|
|
335
|
+
*/
|
|
336
|
+
export function isMiddayBreakPrint(
|
|
337
|
+
timestampMs: number,
|
|
338
|
+
exchange: string | undefined,
|
|
339
|
+
now: number,
|
|
340
|
+
feedLagMs: number,
|
|
341
|
+
): boolean {
|
|
342
|
+
const canonical = canonicalExchange(exchange);
|
|
343
|
+
const pause = MIDDAY_BREAKS[canonical];
|
|
344
|
+
const timeZone = pause?.timeZone ?? EXCHANGE_TIME_ZONES[canonical];
|
|
345
|
+
if (!pause || !timeZone || !Number.isFinite(timestampMs) || !Number.isFinite(now) || timestampMs > now) return false;
|
|
346
|
+
const { year, month, day } = zonedDateTimeParts(now, timeZone);
|
|
347
|
+
const weekday = new Date(Date.UTC(year, month - 1, day)).getUTCDay();
|
|
348
|
+
if (weekday === 0 || weekday === 6) return false;
|
|
349
|
+
const [start, end] = weekday === 5 && pause.friday ? pause.friday : pause.weekdays;
|
|
350
|
+
const at = (minutes: number) => zonedWallClockToUtcMs(timeZone, year, month, day, Math.floor(minutes / 60), minutes % 60, 0);
|
|
351
|
+
const breakStart = at(start);
|
|
352
|
+
return now >= breakStart && now <= at(end) + feedLagMs + MIDDAY_BREAK_MARGIN_MS
|
|
353
|
+
&& timestampMs >= breakStart - MIDDAY_BREAK_MARGIN_MS;
|
|
354
|
+
}
|
|
355
|
+
|
|
284
356
|
function usSessionState(timestampMs: number): UsSessionState {
|
|
285
357
|
const minute = Math.floor(timestampMs / 60_000);
|
|
286
358
|
return perMinute(usSessionCache, minute, () => formatUsSessionState(minute * 60_000));
|
|
@@ -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
|
+
}
|