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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useMemo, useRef, useState } from "react";
|
|
1
|
+
import { useCallback, useMemo, useRef, useState, type ReactNode } from "react";
|
|
2
2
|
import {
|
|
3
3
|
DataTableView,
|
|
4
4
|
usePaneFooter,
|
|
@@ -8,34 +8,42 @@ import {
|
|
|
8
8
|
type PaneFooterSegment,
|
|
9
9
|
} from "../../../components";
|
|
10
10
|
import { handleRefreshKey } from "../../../components/data-table/table-pane";
|
|
11
|
+
import { CountryFlag } from "../../../components/ui/country-flag";
|
|
11
12
|
import { getSharedMarketDataCoordinator } from "../../../market-data/coordinator";
|
|
12
13
|
import { useFxRatesMap } from "../../../market-data/hooks";
|
|
13
14
|
import { resolveEntryData } from "../../../market-data/selectors";
|
|
14
15
|
import { usePaneSettingValue } from "../../../state/app/context";
|
|
15
16
|
import { colors } from "../../../theme/colors";
|
|
16
17
|
import type { PaneProps } from "../../../types/plugin";
|
|
17
|
-
import { TextAttributes } from "../../../ui";
|
|
18
|
+
import { TextAttributes, useUiCapabilities } from "../../../ui";
|
|
18
19
|
import { useAssetData } from "../../runtime";
|
|
19
20
|
import { summarizeFxRates, fxStatusLabel } from "../../../utils/fx-status";
|
|
20
21
|
import type { PluginModule } from "../plugin-module";
|
|
21
22
|
import { useLiveQuoteEntries } from "../../../state/hooks/quote-streaming";
|
|
22
23
|
import { useAutoRefresh, useUpdatedAgo } from "../../../react/auto-refresh";
|
|
23
24
|
import { useLiveStreamingSetting } from "../../../state/hooks/live-streaming";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
25
|
+
import { fxLegQuoteKey, fxLegReferenceRate, fxLegTargets, fxLegs, fxLegsBehind, liveFxLegEntry } from "./live-legs";
|
|
26
|
+
import { CURRENCY_FLAG_REGIONS, FX_CURRENCIES, formatRate, resolveCurrencies, type FxCurrency } from "./pairs";
|
|
27
|
+
import { crossMovePercent, directionTint, nextTintLevel } from "./direction";
|
|
28
|
+
import { fxMatrixSettings } from "./settings";
|
|
27
29
|
import { createFxExportMetadata } from "./export";
|
|
28
30
|
|
|
29
31
|
const FX_MATRIX_PANE_ID = "fx-matrix";
|
|
30
32
|
/** Stable identity: a fresh literal here would reload the board every render. */
|
|
31
33
|
const NO_SAVED_CURRENCIES: string[] = [];
|
|
32
34
|
const BASE_COLUMN_WIDTH = 5;
|
|
35
|
+
/** Room for a flag, a space and the code once the desktop draws the flag. */
|
|
36
|
+
const FLAGGED_BASE_COLUMN_WIDTH = 6;
|
|
37
|
+
const CURRENCY_FLAGS = new Map<string, ReactNode>(
|
|
38
|
+
FX_CURRENCIES.map((currency) => [currency, <CountryFlag region={CURRENCY_FLAG_REGIONS[currency]} />]),
|
|
39
|
+
);
|
|
33
40
|
const RATE_COLUMN_WIDTH = 10;
|
|
34
41
|
/** Snapshot rates reload at this pace while the feed is not carrying every leg. */
|
|
35
42
|
const FX_FALLBACK_REFRESH_MS = 60_000;
|
|
36
43
|
|
|
37
44
|
function FxMatrixPane({ focused, width, height }: PaneProps) {
|
|
38
45
|
const dataProvider = useAssetData();
|
|
46
|
+
const flagged = useUiCapabilities().nativePaneChrome === true;
|
|
39
47
|
const [savedCurrencies] = usePaneSettingValue<string[]>("currencies", NO_SAVED_CURRENCIES);
|
|
40
48
|
const currencies = useMemo(() => resolveCurrencies(savedCurrencies), [savedCurrencies]);
|
|
41
49
|
const [selectedCurrency, setSelectedCurrency] = useState<string | null>(null);
|
|
@@ -80,6 +88,22 @@ function FxMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
80
88
|
}
|
|
81
89
|
return references;
|
|
82
90
|
}, [legEntries, legs, rates]);
|
|
91
|
+
// A cell's direction is its cross against the pair's previous close. Only a
|
|
92
|
+
// leg whose rate is the live quote's and whose quote carries a previous close
|
|
93
|
+
// counts, USD (the base) as 1: the first rate this pane drew is no daily
|
|
94
|
+
// reference, and a snapshot rate or a stale quote has no previous close to
|
|
95
|
+
// read against.
|
|
96
|
+
const directionReferences = useMemo(() => {
|
|
97
|
+
const references = new Map<string, number>([["USD", 1]]);
|
|
98
|
+
for (const leg of legs) {
|
|
99
|
+
if (!liveEntries.has(leg.currency)) continue;
|
|
100
|
+
const reference = fxLegReferenceRate(leg, legEntries.get(fxLegQuoteKey(leg)));
|
|
101
|
+
if (reference != null) references.set(leg.currency, reference);
|
|
102
|
+
}
|
|
103
|
+
return references;
|
|
104
|
+
}, [legEntries, legs, liveEntries]);
|
|
105
|
+
// The step each cell showed last, which a tick near a boundary keeps.
|
|
106
|
+
const tintLevels = useRef(new Map<string, number>());
|
|
83
107
|
// Export the provenance of this render's rates, even if a provider response
|
|
84
108
|
// arrives before React commits the next render and the user exports now.
|
|
85
109
|
const rateEntries = new Map(currencies.map((currency) => {
|
|
@@ -99,47 +123,59 @@ function FxMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
99
123
|
// current relaxes the snapshot reload: a quote another pane loaded, or one
|
|
100
124
|
// the stream stopped sending, would otherwise freeze the matrix. With
|
|
101
125
|
// streaming off, the legs' own quote poll is the feed.
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
126
|
+
const legsBehind = fxLegsBehind(legs, legEntries, {
|
|
127
|
+
liveStreaming,
|
|
128
|
+
liveCurrencies: new Set(liveEntries.keys()),
|
|
129
|
+
startedAt: subscriptionStartedAt,
|
|
130
|
+
now: freshnessNow,
|
|
106
131
|
});
|
|
132
|
+
const allLegsLive = legsBehind.length === 0;
|
|
107
133
|
|
|
108
|
-
const
|
|
134
|
+
const reload = useCallback((codes: readonly string[]) => {
|
|
109
135
|
const coordinator = getSharedMarketDataCoordinator();
|
|
110
136
|
if (!coordinator) return;
|
|
111
|
-
for (const currency of
|
|
137
|
+
for (const currency of codes) {
|
|
112
138
|
if (currency === "USD") continue;
|
|
113
139
|
void coordinator.loadFxRate(currency, { forceRefresh: true }).catch(() => {});
|
|
114
140
|
}
|
|
115
|
-
}, [
|
|
141
|
+
}, []);
|
|
142
|
+
const refresh = useCallback(() => reload(currencies), [currencies, reload]);
|
|
116
143
|
|
|
117
|
-
|
|
144
|
+
// The reload that stands in for the feed asks only for the legs it is
|
|
145
|
+
// behind on: a thin pair that rarely ticks must not make every selected
|
|
146
|
+
// currency reload each minute.
|
|
147
|
+
useAutoRefresh(snapshotFetchedAt || null, () => reload(allLegsLive ? currencies : legsBehind), {
|
|
148
|
+
intervalMs: allLegsLive ? null : FX_FALLBACK_REFRESH_MS,
|
|
149
|
+
});
|
|
118
150
|
|
|
119
151
|
const columns = useMemo<DataTableColumn[]>(() => [
|
|
120
|
-
{ id: "base", label: "", width: BASE_COLUMN_WIDTH, align: "left" },
|
|
152
|
+
{ id: "base", label: "", width: flagged ? FLAGGED_BASE_COLUMN_WIDTH : BASE_COLUMN_WIDTH, align: "left" },
|
|
121
153
|
...currencies.map((currency) => ({
|
|
122
154
|
id: currency,
|
|
123
155
|
label: currency,
|
|
124
156
|
width: RATE_COLUMN_WIDTH,
|
|
125
157
|
align: "right" as const,
|
|
158
|
+
headerLeading: flagged ? CURRENCY_FLAGS.get(currency) : undefined,
|
|
126
159
|
})),
|
|
127
|
-
], [currencies]);
|
|
160
|
+
], [currencies, flagged]);
|
|
128
161
|
|
|
129
162
|
const renderCell = useCallback((
|
|
130
|
-
row:
|
|
163
|
+
row: FxCurrency,
|
|
131
164
|
column: DataTableColumn,
|
|
165
|
+
_index: number,
|
|
166
|
+
rowState: { selected: boolean },
|
|
132
167
|
): DataTableCell => {
|
|
133
168
|
if (column.id === "base") {
|
|
134
169
|
return {
|
|
135
170
|
text: row,
|
|
136
171
|
color: colors.textBright,
|
|
137
172
|
attributes: TextAttributes.BOLD,
|
|
173
|
+
leading: flagged ? CURRENCY_FLAGS.get(row) : undefined,
|
|
138
174
|
};
|
|
139
175
|
}
|
|
140
176
|
|
|
141
|
-
const quoteCurrency = column.id as
|
|
142
|
-
if (row === quoteCurrency) return { text: formatRate(1
|
|
177
|
+
const quoteCurrency = column.id as FxCurrency;
|
|
178
|
+
if (row === quoteCurrency) return { text: formatRate(1), color: colors.textDim };
|
|
143
179
|
|
|
144
180
|
const base = rates.get(row);
|
|
145
181
|
const quote = rates.get(quoteCurrency);
|
|
@@ -150,8 +186,21 @@ function FxMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
150
186
|
return { text: pending ? "…" : "—", color: colors.textDim };
|
|
151
187
|
}
|
|
152
188
|
const reference = (referenceRates.get(row) ?? base) / (referenceRates.get(quoteCurrency) ?? quote);
|
|
153
|
-
|
|
154
|
-
|
|
189
|
+
const rowReference = directionReferences.get(row);
|
|
190
|
+
const columnReference = directionReferences.get(quoteCurrency);
|
|
191
|
+
const level = nextTintLevel(
|
|
192
|
+
tintLevels.current,
|
|
193
|
+
`${row}/${quoteCurrency}`,
|
|
194
|
+
rowReference != null && columnReference != null
|
|
195
|
+
? crossMovePercent(base, rowReference, quote, columnReference)
|
|
196
|
+
: null,
|
|
197
|
+
);
|
|
198
|
+
// The cursor row keeps its selection colours; the tint leans on them.
|
|
199
|
+
const backgroundColor = rowState.selected
|
|
200
|
+
? directionTint(level, { background: colors.selected, text: colors.selectedText })
|
|
201
|
+
: directionTint(level, { background: colors.bg, text: colors.text });
|
|
202
|
+
return { text: formatRate(base / quote, reference), color: colors.text, backgroundColor };
|
|
203
|
+
}, [directionReferences, flagged, rates, referenceRates, status.loading]);
|
|
155
204
|
|
|
156
205
|
const handleKeyDown = useCallback((event: DataTableKeyEvent) => handleRefreshKey(event, refresh), [refresh]);
|
|
157
206
|
|
|
@@ -166,7 +215,7 @@ function FxMatrixPane({ focused, width, height }: PaneProps) {
|
|
|
166
215
|
}, [status.loading, statusText, updatedAgo]);
|
|
167
216
|
|
|
168
217
|
return (
|
|
169
|
-
<DataTableView<
|
|
218
|
+
<DataTableView<FxCurrency>
|
|
170
219
|
focused={focused}
|
|
171
220
|
selection={{
|
|
172
221
|
kind: "id",
|
|
@@ -203,18 +252,7 @@ export const fxMatrixModule: PluginModule = {
|
|
|
203
252
|
defaultMode: "floating",
|
|
204
253
|
defaultFloatingSize: { width: 105, height: 14 },
|
|
205
254
|
tableExport: true,
|
|
206
|
-
settings:
|
|
207
|
-
title: "FX Cross Rates Settings",
|
|
208
|
-
values: {
|
|
209
|
-
currencies: resolveCurrencies(context.settings.currencies as string[] | undefined),
|
|
210
|
-
},
|
|
211
|
-
fields: [{
|
|
212
|
-
key: "currencies",
|
|
213
|
-
label: "Currencies",
|
|
214
|
-
type: "ordered-multi-select",
|
|
215
|
-
options: MAJOR_CURRENCIES.map((currency) => ({ value: currency, label: currency })),
|
|
216
|
-
}],
|
|
217
|
-
}),
|
|
255
|
+
settings: fxMatrixSettings,
|
|
218
256
|
},
|
|
219
257
|
],
|
|
220
258
|
|
|
@@ -2,6 +2,7 @@ import type { QueryEntry } from "../../../market-data/result-types";
|
|
|
2
2
|
import { buildQuoteKey, resolveEntryData } from "../../../market-data/selectors";
|
|
3
3
|
import type { QuoteSubscriptionTarget } from "../../../types/data-provider";
|
|
4
4
|
import type { Quote } from "../../../types/financials";
|
|
5
|
+
import { isStreamCarryingQuote } from "../shared/use-quote-board";
|
|
5
6
|
|
|
6
7
|
/** Currencies the market quotes as USD per unit; the rest quote as units per USD. */
|
|
7
8
|
const USD_QUOTED = new Set(["EUR", "GBP", "AUD", "NZD"]);
|
|
@@ -69,6 +70,22 @@ export function liveFxLegEntry(
|
|
|
69
70
|
};
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
/**
|
|
74
|
+
* The legs the feed is not carrying, whose snapshot rates a reload has to
|
|
75
|
+
* stand in for. With streaming off the legs' own quote poll is the feed.
|
|
76
|
+
*/
|
|
77
|
+
export function fxLegsBehind(
|
|
78
|
+
legs: readonly FxLeg[],
|
|
79
|
+
entries: ReadonlyMap<string, QueryEntry<Quote>>,
|
|
80
|
+
feed: { liveStreaming: boolean; liveCurrencies: ReadonlySet<string>; startedAt: number; now: number },
|
|
81
|
+
): string[] {
|
|
82
|
+
return legs.filter((leg) => {
|
|
83
|
+
const entry = entries.get(fxLegQuoteKey(leg));
|
|
84
|
+
if (!feed.liveStreaming) return !(feed.liveCurrencies.has(leg.currency) && (entry?.fetchedAt ?? 0) >= feed.startedAt);
|
|
85
|
+
return !isStreamCarryingQuote(entry, feed.startedAt, feed.now);
|
|
86
|
+
}).map((leg) => leg.currency);
|
|
87
|
+
}
|
|
88
|
+
|
|
72
89
|
/** USD per unit at the pair's previous close: a rate that holds still for the session. */
|
|
73
90
|
export function fxLegReferenceRate(leg: FxLeg, entry: QueryEntry<Quote> | undefined): number | null {
|
|
74
91
|
const close = resolveEntryData(entry)?.previousClose;
|
|
@@ -1,27 +1,81 @@
|
|
|
1
|
-
|
|
1
|
+
/** The default board, in its default order. */
|
|
2
2
|
export const MAJOR_CURRENCIES = ["USD", "EUR", "GBP", "JPY", "CHF", "CAD", "AUD", "NZD"] as const;
|
|
3
|
-
export type MajorCurrency = typeof MAJOR_CURRENCIES[number];
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
* Every currency the board can carry, in the order its settings list them: the
|
|
6
|
+
* majors, the other liquid currencies, then emerging markets by region.
|
|
7
|
+
*/
|
|
8
|
+
export const FX_CURRENCIES = [
|
|
9
|
+
...MAJOR_CURRENCIES,
|
|
10
|
+
"SEK", "NOK", "DKK", "HKD", "SGD", "CNY", "CNH",
|
|
11
|
+
"KRW", "TWD", "INR", "IDR", "MYR", "PHP", "THB", "VND", "PKR",
|
|
12
|
+
"PLN", "CZK", "HUF", "RON", "UAH", "TRY", "KZT",
|
|
13
|
+
"ILS", "SAR", "AED", "QAR", "EGP", "ZAR", "NGN", "KES",
|
|
14
|
+
"MXN", "BRL", "CLP", "COP", "PEN", "ARS",
|
|
15
|
+
] as const;
|
|
16
|
+
export type FxCurrency = typeof FX_CURRENCIES[number];
|
|
17
|
+
|
|
18
|
+
/** The flag each currency wears on the desktop and web; the euro is the EU's, not one member's. */
|
|
19
|
+
export const CURRENCY_FLAG_REGIONS: Record<FxCurrency, string> = {
|
|
20
|
+
USD: "US", EUR: "EU", GBP: "GB", JPY: "JP", CHF: "CH", CAD: "CA", AUD: "AU", NZD: "NZ",
|
|
21
|
+
SEK: "SE", NOK: "NO", DKK: "DK", HKD: "HK", SGD: "SG", CNY: "CN", CNH: "CN",
|
|
22
|
+
KRW: "KR", TWD: "TW", INR: "IN", IDR: "ID", MYR: "MY", PHP: "PH", THB: "TH", VND: "VN", PKR: "PK",
|
|
23
|
+
PLN: "PL", CZK: "CZ", HUF: "HU", RON: "RO", UAH: "UA", TRY: "TR", KZT: "KZ",
|
|
24
|
+
ILS: "IL", SAR: "SA", AED: "AE", QAR: "QA", EGP: "EG", ZAR: "ZA", NGN: "NG", KES: "KE",
|
|
25
|
+
MXN: "MX", BRL: "BR", CLP: "CL", COP: "CO", PEN: "PE", ARS: "AR",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** One-pick selections in the pane settings. Each fills the currency list, which stays editable. */
|
|
29
|
+
export const CURRENCY_SETS: readonly { id: string; label: string; currencies: readonly FxCurrency[] }[] = [
|
|
30
|
+
{ id: "majors", label: "Majors", currencies: MAJOR_CURRENCIES },
|
|
31
|
+
{ id: "g10", label: "G10", currencies: [...MAJOR_CURRENCIES, "SEK", "NOK"] },
|
|
32
|
+
{
|
|
33
|
+
id: "asia",
|
|
34
|
+
label: "Asia",
|
|
35
|
+
currencies: ["USD", "JPY", "CNY", "CNH", "HKD", "SGD", "TWD", "KRW", "INR", "IDR", "MYR", "PHP", "THB", "VND", "PKR"],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "emea",
|
|
39
|
+
label: "EMEA",
|
|
40
|
+
currencies: [
|
|
41
|
+
"USD", "EUR", "GBP", "CHF", "SEK", "NOK", "DKK", "PLN", "CZK", "HUF", "RON", "UAH", "TRY", "KZT",
|
|
42
|
+
"ILS", "SAR", "AED", "QAR", "EGP", "ZAR", "NGN", "KES",
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
{ id: "americas", label: "Americas", currencies: ["USD", "CAD", "MXN", "BRL", "CLP", "COP", "PEN", "ARS"] },
|
|
46
|
+
{ id: "all", label: "All", currencies: FX_CURRENCIES },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Decimals follow the rate's size, counted at `referenceRate` (the cross at a
|
|
51
|
+
* rate that holds still) when there is one, so a live rate ticking across a
|
|
52
|
+
* power of ten, such as JPY/AUD near 0.0100, keeps its decimals. From 50 up a
|
|
53
|
+
* rate reads two decimals (149.25, 1340.50, 33000.12); below 0.1 it keeps five
|
|
54
|
+
* significant digits, to eight decimals; everything between reads four.
|
|
10
55
|
*/
|
|
11
|
-
export function formatRate(rate: number,
|
|
56
|
+
export function formatRate(rate: number, referenceRate = rate): string {
|
|
12
57
|
if (!Number.isFinite(rate) || rate <= 0) return "—";
|
|
13
58
|
const basis = Number.isFinite(referenceRate) && referenceRate > 0 ? referenceRate : rate;
|
|
14
|
-
const decimals = basis < 0.1 ? Math.min(8, 4 - Math.floor(Math.log10(basis))) :
|
|
59
|
+
const decimals = basis < 0.1 ? Math.min(8, 4 - Math.floor(Math.log10(basis))) : basis >= 50 ? 2 : 4;
|
|
15
60
|
return rate.toFixed(decimals);
|
|
16
61
|
}
|
|
17
62
|
|
|
63
|
+
function isFxCurrency(code: unknown): code is FxCurrency {
|
|
64
|
+
return typeof code === "string" && FX_CURRENCIES.includes(code as FxCurrency);
|
|
65
|
+
}
|
|
66
|
+
|
|
18
67
|
/**
|
|
19
|
-
* The saved currency selection, falling back to the majors
|
|
20
|
-
* holds
|
|
68
|
+
* The saved currency selection in its saved order, falling back to the majors
|
|
69
|
+
* when it is empty or holds no code this board carries. Unknown codes and
|
|
70
|
+
* repeats drop out. A string is a typed list, as in `--currencies USD,EUR` or
|
|
71
|
+
* `--currencies asia`: codes and set names, in any case.
|
|
21
72
|
*/
|
|
22
|
-
export function resolveCurrencies(saved?:
|
|
23
|
-
const
|
|
24
|
-
(
|
|
25
|
-
|
|
73
|
+
export function resolveCurrencies(saved?: unknown): FxCurrency[] {
|
|
74
|
+
const codes: readonly unknown[] = typeof saved === "string"
|
|
75
|
+
? saved.split(/[\s,]+/).flatMap((token): readonly string[] => (
|
|
76
|
+
CURRENCY_SETS.find((set) => set.id === token.toLowerCase())?.currencies ?? [token.toUpperCase()]
|
|
77
|
+
))
|
|
78
|
+
: Array.isArray(saved) ? saved : [];
|
|
79
|
+
const resolved = [...new Set(codes.filter(isFxCurrency))];
|
|
26
80
|
return resolved.length > 0 ? resolved : [...MAJOR_CURRENCIES];
|
|
27
81
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { PaneSettingsContext, PaneSettingsDef } from "../../../types/plugin";
|
|
2
|
+
import { CURRENCY_SETS, FX_CURRENCIES, resolveCurrencies } from "./pairs";
|
|
3
|
+
|
|
4
|
+
const CUSTOM_SET = "custom";
|
|
5
|
+
|
|
6
|
+
let currencyNames: Intl.DisplayNames | null | undefined;
|
|
7
|
+
|
|
8
|
+
/** ISO has no code for the offshore yuan, so the runtime has no name for it. */
|
|
9
|
+
const CURRENCY_NAMES: Partial<Record<string, string>> = { CNH: "Chinese Yuan (Offshore)" };
|
|
10
|
+
|
|
11
|
+
/** A currency's English name for the picker, or null where the runtime has no names. */
|
|
12
|
+
function currencyName(code: string): string | null {
|
|
13
|
+
if (CURRENCY_NAMES[code]) return CURRENCY_NAMES[code]!;
|
|
14
|
+
try {
|
|
15
|
+
currencyNames ??= new Intl.DisplayNames(["en"], { type: "currency" });
|
|
16
|
+
const name = currencyNames.of(code);
|
|
17
|
+
return name && name !== code ? name : null;
|
|
18
|
+
} catch {
|
|
19
|
+
currencyNames = null;
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Currencies are chosen as an ordered list. A set fills that list in one pick;
|
|
26
|
+
* the list stays editable, and reads as Custom once it stops matching a set.
|
|
27
|
+
*/
|
|
28
|
+
export function fxMatrixSettings(context: PaneSettingsContext): PaneSettingsDef {
|
|
29
|
+
const currencies = resolveCurrencies(context.settings.currencies);
|
|
30
|
+
const matching = CURRENCY_SETS.find((set) => (
|
|
31
|
+
set.currencies.length === currencies.length && set.currencies.every((code, index) => code === currencies[index])
|
|
32
|
+
));
|
|
33
|
+
return {
|
|
34
|
+
title: "FX Cross Rates Settings",
|
|
35
|
+
values: { currencies, currencySet: matching?.id ?? CUSTOM_SET },
|
|
36
|
+
fields: [
|
|
37
|
+
{
|
|
38
|
+
key: "currencySet",
|
|
39
|
+
label: "Currency set",
|
|
40
|
+
type: "select",
|
|
41
|
+
options: [
|
|
42
|
+
...CURRENCY_SETS.map((set) => ({ value: set.id, label: set.label })),
|
|
43
|
+
{ value: CUSTOM_SET, label: "Custom" },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: "currencies",
|
|
48
|
+
label: "Currencies",
|
|
49
|
+
type: "ordered-multi-select",
|
|
50
|
+
searchable: true,
|
|
51
|
+
options: FX_CURRENCIES.map((code) => ({ value: code, label: code, description: currencyName(code) ?? undefined })),
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
applyValue: (settings, field, value) => {
|
|
55
|
+
if (field.key !== "currencySet") return { ...settings, [field.key]: value };
|
|
56
|
+
// The set is a way to fill the list, never a setting of its own.
|
|
57
|
+
const { currencySet: _unused, ...rest } = settings;
|
|
58
|
+
const set = CURRENCY_SETS.find((candidate) => candidate.id === value);
|
|
59
|
+
return set ? { ...rest, currencies: [...set.currencies] } : rest;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { GpuObservation } from "../../../api-client/gpu";
|
|
|
2
2
|
import type { HeadlessPaneDefinition } from "../../../types/plugin";
|
|
3
3
|
import { fetchGpuBoard, fetchGpuEvents, fetchGpuHistory, loadGpuEquityHistory } from "./client";
|
|
4
4
|
import { GPU_TABS, gpuArgument, gpuBasisLabel, gpuChange, gpuEquityRows, gpuEventDate, gpuProvenanceLabel, gpuLabel, gpuRows, gpuSource, gpuTab } from "./model";
|
|
5
|
+
import { quoteFreshnessFields } from "../shared/report-freshness";
|
|
5
6
|
|
|
6
7
|
const observationRow = (row: GpuObservation) => ({ gpu: gpuLabel(row), source: gpuSource(row), basis: gpuBasisLabel(row.basis),
|
|
7
8
|
price: row.pricePerGpuHr, availability: row.availability, observedAt: row.observedAt, effectiveAt: row.effectiveAt, provenance: row.provenance ?? "live", provenanceLabel: gpuProvenanceLabel(row, true),
|
|
@@ -26,9 +27,11 @@ export const gpuHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
26
27
|
const tab = gpuTab(args.options.tab);
|
|
27
28
|
const board = await fetchGpuBoard(ctx.apiClient);
|
|
28
29
|
const metadata = { asOf: board.asOf, stale: board.stale, complete: board.status === "available" && !board.access?.locked, unit: "USD/GPU-hour", access: board.access };
|
|
30
|
+
// Prices observed on providers' pages, not a feed; each board row says whether its source has gone quiet.
|
|
31
|
+
const freshness = { source: "GPU cloud providers", status: "not-a-feed" as const, basis: "observed prices" };
|
|
29
32
|
if (tab === "history") {
|
|
30
33
|
const history = await fetchGpuHistory({ ...(model ? { gpuModel: model } : {}), limit: 10_000 }, ctx.apiClient);
|
|
31
|
-
return { sections: [{ title: "Dated observations", columns: [...columns.filter((column) => !column.key.startsWith("change")), { key: "provenanceLabel", header: "Record" }], rows: history.points.map(observationRow) }], complete: !history.access?.locked, metadata: { ...metadata, access: history.access ?? board.access }, errors: board.gaps };
|
|
34
|
+
return { sections: [{ title: "Dated observations", columns: [...columns.filter((column) => !column.key.startsWith("change")), { key: "provenanceLabel", header: "Record" }], rows: history.points.map(observationRow) }], freshness: { ...freshness, oldest: null }, complete: !history.access?.locked, metadata: { ...metadata, access: history.access ?? board.access }, errors: board.gaps };
|
|
32
35
|
}
|
|
33
36
|
if (tab === "changes") {
|
|
34
37
|
const payload = await fetchGpuEvents(model || undefined, ctx.apiClient);
|
|
@@ -41,7 +44,7 @@ export const gpuHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
41
44
|
oldPrice: event.oldPrice, newPrice: event.newPrice, changePct: event.changePct, kind: event.kind,
|
|
42
45
|
oldMembers: event.oldMembers, newMembers: event.newMembers, provenance: event.provenance ?? "live",
|
|
43
46
|
provenanceLabel: gpuProvenanceLabel(event, true), evidenceUrl: event.evidenceUrl ?? null, sourceUrl: event.sourceUrl ?? null,
|
|
44
|
-
oldAvailability: event.oldAvailability ?? null, newAvailability: event.newAvailability ?? null })) }], complete: !payload.access?.locked, metadata: { ...metadata, access: payload.access ?? board.access }, errors: board.gaps };
|
|
47
|
+
oldAvailability: event.oldAvailability ?? null, newAvailability: event.newAvailability ?? null })) }], freshness: { ...freshness, oldest: null }, complete: !payload.access?.locked, metadata: { ...metadata, access: payload.access ?? board.access }, errors: board.gaps };
|
|
45
48
|
}
|
|
46
49
|
if (tab === "equities") {
|
|
47
50
|
const related = gpuEquityRows(board.rows, model || "H100");
|
|
@@ -51,6 +54,7 @@ export const gpuHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
51
54
|
const history = histories.find((entry) => entry.symbol === row.symbol);
|
|
52
55
|
return { symbol: row.symbol, role: row.role, price: quote?.price ?? null, change1d: quote?.changePercent ?? null,
|
|
53
56
|
change5d: history?.value ?? null, fiveDayAsOf: history?.asOf ?? null, quoteAsOf: quote?.lastUpdated ? new Date(quote.lastUpdated).toISOString() : null,
|
|
57
|
+
...quoteFreshnessFields(quote),
|
|
54
58
|
gpu: row.reference ? gpuLabel(row.reference) : row.gpuModel, gpuSource: row.reference ? gpuSource(row.reference) : null, gpuChange7d: row.reference?.change7d ?? null };
|
|
55
59
|
}));
|
|
56
60
|
return { sections: [{ title: "Related equities", columns: [
|
|
@@ -62,6 +66,6 @@ export const gpuHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
62
66
|
}
|
|
63
67
|
const rows = gpuRows(board.rows, model).map((row) => ({ ...observationRow(row), change1d: row.change1d, change7d: row.change7d,
|
|
64
68
|
change30d: row.change30d, stale: row.stale, sample: row.stats ?? null }));
|
|
65
|
-
return { sections: [{ title: "GPU rental prices", columns, rows }], complete: !board.access?.locked, metadata, errors: board.gaps };
|
|
69
|
+
return { sections: [{ title: "GPU rental prices", columns, rows }], freshness, complete: !board.access?.locked, metadata, errors: board.gaps };
|
|
66
70
|
},
|
|
67
71
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Box, Span, Text, TextAttributes, useUiCapabilities } from "../../../ui";
|
|
2
2
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
3
3
|
import { blendHex } from "../../../theme/colors";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { truncateToDisplayWidth } from "../../../utils/format";
|
|
5
|
+
import { gpuAxisLabels, gpuBasisColor, gpuBasisLabel, gpuPrice, type GpuAxisLabel, type GpuLadderRow } from "./model";
|
|
6
6
|
|
|
7
7
|
const LABEL_CELLS = 28;
|
|
8
8
|
const VALUE_CELLS = 17;
|
|
@@ -10,14 +10,13 @@ const VALUE_CELLS = 17;
|
|
|
10
10
|
const position = (value: number, low: number, high: number) => high > low ? (value - low) / (high - low) : 0.5;
|
|
11
11
|
const percent = (ratio: number) => `${(Math.max(0, Math.min(1, ratio)) * 100).toFixed(2)}%`;
|
|
12
12
|
|
|
13
|
-
/** The domain every basis shares, padded
|
|
14
|
-
function gpuLadderDomain(rows: readonly GpuLadderRow[]): { low: number; high: number
|
|
13
|
+
/** The domain every basis shares, padded so the ends never touch a band. */
|
|
14
|
+
function gpuLadderDomain(rows: readonly GpuLadderRow[]): { low: number; high: number } | null {
|
|
15
15
|
if (!rows.length) return null;
|
|
16
16
|
const min = Math.min(...rows.map((row) => row.min));
|
|
17
17
|
const max = Math.max(...rows.map((row) => row.max));
|
|
18
18
|
const pad = Math.max((max - min) * 0.04, max * 0.02, 0.05);
|
|
19
|
-
|
|
20
|
-
return { low, high, ticks: gpuAxisTicks(low, high).filter((tick) => tick >= low && tick <= high) };
|
|
19
|
+
return { low: Math.max(0, min - pad), high: max + pad };
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
/** Terminal cells of one track: thin rule for the range, heavy for the quartiles, a bar at the median. */
|
|
@@ -51,7 +50,10 @@ export function GpuPriceLadder({ rows, width, height, selected }: {
|
|
|
51
50
|
const valueCells = wide ? VALUE_CELLS : 6;
|
|
52
51
|
// Two cells of padding, two gaps, and one spare so the value never clips.
|
|
53
52
|
const trackCellsWidth = Math.max(8, width - labelCells - valueCells - 5);
|
|
54
|
-
const { low, high
|
|
53
|
+
const { low, high } = domain;
|
|
54
|
+
// Labels may hang into the empty label and value columns of the axis row, so the end ticks stay centred.
|
|
55
|
+
const room = { left: labelCells + 1, right: valueCells + 1 };
|
|
56
|
+
const labels = gpuAxisLabels(low, high, trackCellsWidth, room);
|
|
55
57
|
return (
|
|
56
58
|
<Box flexDirection="column" width={width} height={shown.length + 1} paddingX={1} data-gloom-role="gpu-price-ladder">
|
|
57
59
|
{shown.map((row) => {
|
|
@@ -91,37 +93,31 @@ export function GpuPriceLadder({ rows, width, height, selected }: {
|
|
|
91
93
|
</Box>
|
|
92
94
|
);
|
|
93
95
|
})}
|
|
94
|
-
<
|
|
95
|
-
<Box width={labelCells} flexShrink={0} />
|
|
96
|
-
<GpuLadderAxis ticks={ticks} low={low} high={high} width={trackCellsWidth} desktop={desktop} />
|
|
97
|
-
</Box>
|
|
96
|
+
<GpuLadderAxis labels={labels} width={trackCellsWidth} room={room} desktop={desktop} />
|
|
98
97
|
</Box>
|
|
99
98
|
);
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Each label centred on its tick, on the scale the bands and markers use. The
|
|
103
|
+
* desktop places real elements by percentage, as it does the markers; the
|
|
104
|
+
* terminal writes the whole axis row so an end label can hang past the track.
|
|
105
|
+
*/
|
|
106
|
+
function GpuLadderAxis({ labels, width, room, desktop }: { labels: readonly GpuAxisLabel[]; width: number; room: { left: number; right: number }; desktop: boolean }) {
|
|
103
107
|
const colors = useThemeColors();
|
|
104
|
-
const label = (tick: number) => `$${Number.isInteger(tick) ? tick : tick.toFixed(1)}`;
|
|
105
108
|
if (desktop) {
|
|
106
109
|
return (
|
|
107
|
-
<Box
|
|
108
|
-
{
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
})}
|
|
110
|
+
<Box flexDirection="row" height={1}>
|
|
111
|
+
<Box width={room.left} flexShrink={0} />
|
|
112
|
+
<Box width={width} height={1} flexShrink={0} style={{ position: "relative" }}>
|
|
113
|
+
{labels.map((label) => <Box key={label.value} style={{ position: "absolute", left: percent(label.ratio), transform: "translateX(-50%)", whiteSpace: "nowrap" }}>
|
|
114
|
+
<Text fg={colors.textDim}>{label.text}</Text>
|
|
115
|
+
</Box>)}
|
|
116
|
+
</Box>
|
|
115
117
|
</Box>
|
|
116
118
|
);
|
|
117
119
|
}
|
|
118
|
-
const line = Array.from({ length: width }, () => " ");
|
|
119
|
-
for (const [
|
|
120
|
-
|
|
121
|
-
const center = Math.round(position(tick, low, high) * (width - 1));
|
|
122
|
-
const start = index === 0 ? 0 : index === ticks.length - 1 ? width - displayWidth(text) : center - Math.floor(text.length / 2);
|
|
123
|
-
if (start < 0 || start + text.length > width || line.slice(Math.max(0, start - 1), start + text.length + 1).some((char) => char !== " ")) continue;
|
|
124
|
-
for (let i = 0; i < text.length; i++) line[start + i] = text[i]!;
|
|
125
|
-
}
|
|
126
|
-
return <Box width={width} height={1} flexShrink={0}><Text fg={colors.textDim}>{line.join("")}</Text></Box>;
|
|
120
|
+
const line = Array.from({ length: room.left + width + room.right }, () => " ");
|
|
121
|
+
for (const label of labels) for (let i = 0; i < label.text.length; i++) line[room.left + label.start + i] = label.text[i]!;
|
|
122
|
+
return <Box height={1} flexShrink={0}><Text fg={colors.textDim}>{line.join("").trimEnd()}</Text></Box>;
|
|
127
123
|
}
|
|
@@ -151,7 +151,7 @@ export function gpuPriceLadder(rows: readonly GpuBoardRow[], model: string): Gpu
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/** Round dollar ticks for a price axis: one, two or five times a power of ten, four to six of them. */
|
|
154
|
-
|
|
154
|
+
function gpuAxisTicks(low: number, high: number): number[] {
|
|
155
155
|
if (!(high > low)) return [low];
|
|
156
156
|
const raw = (high - low) / 5;
|
|
157
157
|
const power = 10 ** Math.floor(Math.log10(raw));
|
|
@@ -161,6 +161,32 @@ export function gpuAxisTicks(low: number, high: number): number[] {
|
|
|
161
161
|
return ticks;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
export interface GpuAxisLabel { value: number; text: string; ratio: number; start: number }
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Labels for a price axis `cells` wide over `low`..`high`: each centred on its
|
|
168
|
+
* tick's own value, on the linear scale the bands and markers use (`ratio`, and
|
|
169
|
+
* `start`, the first cell on the terminal), with the decimals the tick step
|
|
170
|
+
* needs so neighbours never read alike ($2.0 $2.1 $2.2, $2.05 $2.10). A label
|
|
171
|
+
* that would touch its neighbour or run past the room beside the axis is left
|
|
172
|
+
* out, never moved off its value.
|
|
173
|
+
*/
|
|
174
|
+
export function gpuAxisLabels(low: number, high: number, cells: number, room: { left: number; right: number } = { left: 0, right: 0 }): GpuAxisLabel[] {
|
|
175
|
+
const ticks = gpuAxisTicks(low, high).filter((tick) => tick >= low && tick <= high);
|
|
176
|
+
const digits = [0, 1, 2, 3].find((places) => ticks.every((tick) => Math.abs(Number(tick.toFixed(places)) - tick) < 1e-9)) ?? 3;
|
|
177
|
+
const labels: GpuAxisLabel[] = [];
|
|
178
|
+
for (const value of ticks) {
|
|
179
|
+
const text = `$${value.toFixed(digits)}`;
|
|
180
|
+
const ratio = high > low ? (value - low) / (high - low) : 0.5;
|
|
181
|
+
// The cell a track draws this value in, so the label's middle sits on the marker's cell.
|
|
182
|
+
const start = Math.round(ratio * (cells - 1)) - Math.floor(text.length / 2);
|
|
183
|
+
const previous = labels.at(-1);
|
|
184
|
+
if (start < -room.left || start + text.length > cells + room.right || (previous && start <= previous.start + previous.text.length)) continue;
|
|
185
|
+
labels.push({ value, text, ratio, start });
|
|
186
|
+
}
|
|
187
|
+
return labels;
|
|
188
|
+
}
|
|
189
|
+
|
|
164
190
|
/** Published notices use their effective date; observed changes use the dated evidence. */
|
|
165
191
|
export const gpuEventDate = (event: Pick<GpuEvent, "origin" | "effectiveAt" | "observedAt">) =>
|
|
166
192
|
event.origin === "published" ? event.effectiveAt ?? event.observedAt : event.observedAt;
|