gloomberb 0.18.2 → 0.18.4
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 +8 -8
- package/README.zh-CN.md +11 -11
- package/bin/{gloomberb → gloom} +3 -1
- package/package.json +6 -2
- package/patches/electrobun@1.18.1.patch +106 -5
- package/src/account/checkout-handoff.tsx +225 -0
- package/src/account/device-signin-dialog.tsx +2 -2
- package/src/account/device-signin.ts +2 -2
- package/src/account/upgrade-dialog.tsx +1 -1
- package/src/api-client/askg.ts +2 -2
- package/src/api-client/auth.ts +2 -2
- package/src/api-client/central-bank-rates.ts +6 -0
- package/src/api-client/collections.ts +5 -1
- package/src/api-client/cot.ts +2 -0
- package/src/api-client/crypto-etf-flows.ts +37 -0
- package/src/api-client/crypto-markets.ts +60 -0
- package/src/api-client/data.ts +99 -5
- package/src/api-client/doe.ts +15 -0
- package/src/api-client/equity-screener.ts +28 -0
- package/src/api-client/exchange-announcements.ts +38 -0
- package/src/api-client/fund-facts.ts +39 -0
- package/src/api-client/futures-curve.ts +9 -1
- package/src/api-client/hiring.ts +301 -0
- package/src/api-client/index.ts +24 -5
- package/src/api-client/market-discovery.ts +14 -0
- package/src/api-client/members.ts +6 -0
- package/src/api-client/mna.ts +6 -0
- package/src/api-client/paths.ts +18 -1
- package/src/api-client/request.ts +26 -7
- package/src/api-client/short-side-publications.ts +37 -0
- package/src/api-client/socket.ts +64 -4
- package/src/api-client/swap-curve.ts +35 -0
- package/src/api-client/telemetry.ts +17 -0
- package/src/api-client/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- package/src/app/global-shortcuts.ts +1 -16
- package/src/app/pane-runtime/plugin-bindings.ts +9 -2
- package/src/app/runtime/desktop-deeplink.ts +5 -5
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +13 -0
- package/src/app/runtime/update.ts +28 -8
- package/src/app/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- package/src/architecture/pane-tabs-allowlist.json +65 -0
- package/src/architecture/ui-literals-allowlist.json +3 -3
- package/src/architecture/ui-tokens-allowlist.json +1 -1
- package/src/brokers/broker-portfolio-sync.ts +37 -0
- package/src/brokers/directory.ts +11 -0
- package/src/brokers/logos.ts +3 -1
- package/src/brokers/signed-in/adapter.ts +304 -26
- package/src/brokers/signed-in/client.ts +14 -2
- package/src/brokers/signed-in/connect.ts +10 -2
- package/src/brokers/sync-broker-instance.ts +9 -1
- package/src/capabilities/chart-series.ts +22 -6
- package/src/cli/bank-section.ts +1 -1
- package/src/cli/base-converter.ts +23 -14
- package/src/cli/central-bank-events.ts +1 -1
- package/src/cli/command-options.ts +59 -4
- package/src/cli/commands/api.ts +9 -6
- package/src/cli/commands/broker.ts +2 -2
- package/src/cli/commands/command-utils.ts +2 -2
- package/src/cli/commands/crypto-hints.ts +7 -20
- package/src/cli/commands/fred-series.ts +4 -2
- package/src/cli/commands/keybindings.ts +2 -2
- package/src/cli/commands/market.ts +1189 -296
- package/src/cli/commands/news-hints.ts +2 -2
- package/src/cli/commands/news-search.ts +59 -6
- package/src/cli/commands/options-leaps.ts +41 -26
- package/src/cli/commands/overview.ts +121 -48
- package/src/cli/commands/plugins.ts +9 -9
- package/src/cli/commands/remote.ts +13 -10
- package/src/cli/commands/search.ts +64 -44
- package/src/cli/commands/system.ts +27 -19
- package/src/cli/commands/themes.ts +1 -1
- package/src/cli/commands/ticker.ts +272 -70
- package/src/cli/context.ts +3 -2
- package/src/cli/desktop-pane-shot-view.ts +2 -2
- package/src/cli/desktop-pane-shot.ts +1 -1
- package/src/cli/earnings-calendar.ts +4 -4
- package/src/cli/entry.ts +18 -1
- package/src/cli/errors.ts +20 -2
- package/src/cli/exit-codes.ts +1 -1
- package/src/cli/export-source.ts +10 -4
- package/src/cli/freshness.ts +2 -8
- package/src/cli/fx-forward.ts +130 -0
- package/src/cli/fx-pair.ts +10 -9
- package/src/cli/glossary.ts +64 -20
- package/src/cli/help.ts +20 -14
- package/src/cli/history-export.ts +126 -0
- package/src/cli/history-rows.ts +196 -43
- package/src/cli/index-roots.ts +5 -45
- package/src/cli/index.ts +32 -18
- package/src/cli/issuer-membership.ts +103 -0
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +315 -43
- package/src/cli/name-entries.ts +73 -22
- package/src/cli/native-smoke.ts +2 -0
- package/src/cli/not-a-ticker.ts +19 -9
- package/src/cli/opentui-libc.ts +5 -0
- package/src/cli/options.ts +12 -0
- package/src/cli/pane-functions/capabilities.ts +77 -20
- package/src/cli/pane-functions/catalog.ts +40 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +12 -8
- package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
- package/src/cli/pane-functions/freshness.ts +174 -23
- package/src/cli/pane-functions/function-help.ts +66 -27
- package/src/cli/pane-functions/headless.ts +48 -16
- package/src/cli/pane-functions/index.ts +82 -21
- package/src/cli/pane-functions/options.ts +22 -2
- package/src/cli/pane-functions/report-notices.ts +12 -4
- package/src/cli/pane-functions/report.ts +5 -5
- package/src/cli/pane-functions/resolver.ts +65 -14
- package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
- package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
- package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
- package/src/cli/pane-functions/screenshot-payload.ts +453 -0
- package/src/cli/pane-functions/screenshot-render.ts +316 -0
- package/src/cli/pane-functions/screenshot-types.ts +162 -0
- package/src/cli/pane-functions/shot-options.ts +8 -3
- package/src/cli/peso-dollar-rates.ts +79 -0
- package/src/cli/quote-answer.ts +38 -3
- package/src/cli/report-tables.ts +190 -27
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +122 -25
- package/src/cli/series-search.ts +5 -5
- package/src/cli/statement-filings.ts +19 -0
- package/src/cli/suffixed-listing-rows.ts +49 -0
- package/src/cli/symbol-args.ts +50 -15
- package/src/cli/symbol-cells.ts +120 -0
- package/src/cli/symbol-list.ts +226 -60
- package/src/cli/symbol-rows.ts +131 -25
- package/src/cli/ticker-resolution.ts +108 -11
- package/src/cli/treasury-yields.ts +5 -5
- package/src/cli/types.ts +2 -0
- package/src/cli/uncovered-instrument.ts +3 -3
- package/src/cli/unknown-command.ts +6 -6
- package/src/components/chart/composite/chart-layout.ts +131 -0
- package/src/components/chart/composite/composite-chart.tsx +387 -21
- package/src/components/chart/composite/drawing-store.ts +26 -6
- package/src/components/chart/composite/interactions.ts +9 -3
- package/src/components/chart/composite/legend.tsx +75 -3
- package/src/components/chart/composite/levels.ts +5 -0
- package/src/components/chart/composite/panel-gestures.ts +41 -0
- package/src/components/chart/composite/panel-labels.ts +2 -1
- package/src/components/chart/composite/panel-surface.tsx +316 -11
- package/src/components/chart/composite/price-axis-labels.tsx +27 -3
- package/src/components/chart/composite/rasterizer.ts +44 -19
- package/src/components/chart/composite/scene.ts +16 -4
- package/src/components/chart/composite/text-renderer.ts +48 -21
- package/src/components/chart/composite/toolbar.tsx +52 -5
- package/src/components/chart/composite/types.ts +19 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
- package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
- package/src/components/chart/composite/use-composite-viewport.ts +12 -3
- package/src/components/chart/composite/value-scale.ts +149 -0
- package/src/components/chart/composite/volume-profile-paint.ts +6 -3
- package/src/components/chart/core/pointer.ts +2 -0
- package/src/components/chart-table/index.ts +2 -0
- package/src/components/chart-table/read.tsx +74 -0
- package/src/components/command-bar/commands/collection-list.ts +41 -19
- package/src/components/command-bar/commands/collection.ts +9 -3
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +3 -2
- package/src/components/command-bar/pane-templates/items.ts +59 -6
- package/src/components/command-bar/pane-templates/workflow.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +32 -6
- package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
- package/src/components/command-bar/routes/root/provider-search.ts +42 -11
- package/src/components/command-bar/routes/root/results.ts +18 -4
- package/src/components/command-bar/routes/root/runtime.ts +15 -3
- package/src/components/command-bar/routes/root/search-providers.ts +25 -2
- package/src/components/command-bar/routes/root/selection.ts +6 -1
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
- package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
- package/src/components/command-bar/selection-runtime.ts +50 -10
- package/src/components/command-bar/surface/index.tsx +24 -2
- package/src/components/command-bar/view-model.ts +7 -0
- package/src/components/command-bar/workflow/broker.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +46 -7
- package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
- package/src/components/command-bar/workflow/fields.ts +8 -2
- package/src/components/command-bar/workflow/ops.ts +18 -4
- package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
- package/src/components/command-bar/workflow/submit.ts +3 -2
- package/src/components/command-bar/workflow/tickers.ts +5 -1
- package/src/components/company-logo.tsx +39 -0
- package/src/components/data-table/sections.ts +4 -2
- package/src/components/data-table/view.tsx +23 -3
- package/src/components/form-modal/confirm.tsx +2 -1
- package/src/components/form-modal/request.ts +5 -0
- package/src/components/form-modal/routes.ts +4 -1
- package/src/components/index.ts +13 -6
- package/src/components/layout/detached-pane-shell.tsx +1 -0
- package/src/components/layout/floating-pane.tsx +1 -0
- package/src/components/layout/header.tsx +234 -60
- package/src/components/layout/market-summary.ts +9 -6
- package/src/components/layout/pane/capture-status.ts +1 -1
- package/src/components/layout/pane/footer/model.ts +11 -5
- package/src/components/layout/pane/header.tsx +10 -3
- package/src/components/layout/pane/index.tsx +1 -0
- package/src/components/layout/pane/pane-tabs.tsx +9 -1
- package/src/components/layout/shell/chrome.ts +19 -6
- package/src/components/layout/shell/index.tsx +2 -1
- package/src/components/layout/shell/pane/layers.tsx +19 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/market-board/index.tsx +11 -3
- package/src/components/onboarding/onboarding-wizard.tsx +1 -0
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
- package/src/components/onboarding/wizard-broker-sync.ts +4 -1
- package/src/components/pane-settings-dialog/desktop.tsx +20 -7
- package/src/components/pane-settings-dialog/tui.tsx +17 -9
- package/src/components/pane-settings-dialog/value.ts +8 -1
- package/src/components/pane-settings-dialog.tsx +44 -13
- package/src/components/sign-in-code-panel.tsx +27 -19
- package/src/components/ui/column-grid.tsx +48 -4
- package/src/components/ui/country-flag-art.tsx +180 -0
- package/src/components/ui/country-flag.tsx +118 -12
- package/src/components/ui/data-table/opentui/index.tsx +61 -2
- package/src/components/ui/data-table/opentui/model.ts +109 -2
- package/src/components/ui/data-table/types.ts +1 -1
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/index.ts +3 -1
- package/src/components/ui/logo-mark.tsx +11 -2
- package/src/components/ui/query-bar.tsx +1 -1
- package/src/components/ui/row-notes.ts +79 -0
- package/src/components/ui/stat-grid.tsx +28 -3
- package/src/components/ui/status.tsx +3 -1
- package/src/core/app-services.ts +4 -0
- package/src/core/state/app/layout.ts +4 -4
- package/src/data/cached-query.ts +8 -1
- package/src/data/config/chart-settings.ts +3 -3
- package/src/data/config/home.ts +10 -2
- package/src/data/config/layout.ts +4 -1
- package/src/data/config/store/node.ts +4 -0
- package/src/data/config/store/normalize.ts +13 -3
- package/src/data/config/store/portfolio-as-of-column.ts +2 -2
- package/src/data/json-storage.ts +2 -0
- package/src/data/saved-copies.ts +84 -0
- package/src/docs/snapshot.json +65 -32
- package/src/i18n/es.ts +51 -12
- package/src/i18n/ja.ts +51 -12
- package/src/i18n/ko.ts +51 -12
- package/src/i18n/zh-cn.ts +51 -12
- package/src/i18n/zh-tw.ts +51 -12
- package/src/layout/desks.ts +1 -1
- package/src/layout/launch-layout.ts +1 -1
- package/src/layout/pane-manager/floating-actions.ts +5 -3
- package/src/layout/pane-manager/floating.ts +43 -1
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/layout/selected-ticker.ts +74 -0
- package/src/market-data/depositary-pair.ts +251 -0
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +124 -40
- package/src/market-data/fx-closes.ts +17 -2
- package/src/market-data/hooks.tsx +19 -11
- package/src/market-data/market/change-basis.ts +49 -7
- package/src/market-data/market/freshness.ts +34 -5
- package/src/market-data/market/period-return.ts +163 -0
- package/src/market-data/market/trading-sessions.ts +13 -0
- package/src/market-data/market/year-to-date.ts +8 -13
- package/src/market-data/performance.ts +20 -14
- package/src/market-data/perpetual-premium.ts +32 -0
- package/src/market-data/published-apac-sessions.ts +2 -1
- package/src/market-data/published-futures-sessions.ts +69 -0
- package/src/market-data/quotes/contributions.ts +5 -1
- package/src/market-data/quotes/freshness.ts +42 -0
- package/src/market-data/quotes/intraday-bar.ts +37 -0
- package/src/market-data/quotes/regular-session-valuation.ts +13 -8
- package/src/market-data/quotes/resolution.ts +4 -2
- package/src/market-data/tax-equivalent.ts +1 -1
- package/src/market-data/ticker-price-returns.ts +3 -1
- package/src/news/aggregator.ts +5 -1
- package/src/news/news-model.ts +4 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/app-notifier.ts +1 -1
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +9 -8
- package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
- package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
- package/src/plugins/builtin/alerts/cli.ts +485 -76
- package/src/plugins/builtin/alerts/command.ts +5 -10
- package/src/plugins/builtin/alerts/event-rows.ts +9 -5
- package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
- package/src/plugins/builtin/alerts/events.ts +108 -5
- package/src/plugins/builtin/alerts/fired-log.ts +78 -0
- package/src/plugins/builtin/alerts/format.ts +2 -1
- package/src/plugins/builtin/alerts/headless.ts +100 -39
- package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
- package/src/plugins/builtin/alerts/history-rows.ts +89 -0
- package/src/plugins/builtin/alerts/index.tsx +45 -18
- package/src/plugins/builtin/alerts/iv-level.ts +365 -0
- package/src/plugins/builtin/alerts/levels.ts +3 -3
- package/src/plugins/builtin/alerts/pane.tsx +97 -29
- package/src/plugins/builtin/alerts/price.ts +35 -0
- package/src/plugins/builtin/alerts/quotes.ts +24 -0
- package/src/plugins/builtin/alerts/research-builder.ts +84 -11
- package/src/plugins/builtin/alerts/research-rules.ts +77 -3
- package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
- package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
- package/src/plugins/builtin/alerts/scheduled.ts +188 -29
- package/src/plugins/builtin/alerts/storage.ts +13 -10
- package/src/plugins/builtin/alerts/targets.ts +12 -3
- package/src/plugins/builtin/analytics/index.tsx +8 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -1
- package/src/plugins/builtin/analytics/risk-book.ts +215 -0
- package/src/plugins/builtin/analytics/risk-client.ts +13 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
- package/src/plugins/builtin/analytics/risk-math.ts +6 -3
- package/src/plugins/builtin/analytics/risk-model.ts +297 -104
- package/src/plugins/builtin/analytics/risk-options.ts +17 -2
- package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
- package/src/plugins/builtin/attention/pane.tsx +22 -16
- package/src/plugins/builtin/awards/headless.ts +7 -3
- package/src/plugins/builtin/awards/model.ts +18 -0
- package/src/plugins/builtin/awards/pane.tsx +12 -9
- package/src/plugins/builtin/backtest/export.ts +1 -1
- package/src/plugins/builtin/backtest/headless.ts +3 -3
- package/src/plugins/builtin/backtest/rules.ts +41 -5
- package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
- package/src/plugins/builtin/broker-manager/footer.ts +27 -11
- package/src/plugins/builtin/broker-manager/index.tsx +21 -12
- package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
- package/src/plugins/builtin/broker-manager/model.ts +12 -2
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
- package/src/plugins/builtin/broker-manager/table.ts +28 -12
- package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
- package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
- package/src/plugins/builtin/broker-trading/controller.ts +45 -13
- package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
- package/src/plugins/builtin/broker-trading/headless.ts +2 -1
- package/src/plugins/builtin/broker-trading/index.tsx +7 -1
- package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
- package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
- package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
- package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
- package/src/plugins/builtin/buildout/cells.tsx +4 -0
- package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
- package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
- package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
- package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
- package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
- package/src/plugins/builtin/catalysts/client.ts +2 -2
- package/src/plugins/builtin/catalysts/detail.tsx +3 -2
- package/src/plugins/builtin/catalysts/index.tsx +1 -1
- package/src/plugins/builtin/catalysts/model.ts +49 -4
- package/src/plugins/builtin/catalysts/pane.tsx +9 -11
- package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
- package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
- package/src/plugins/builtin/changelog/index.tsx +1 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
- package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
- package/src/plugins/builtin/chart-composer/headless.ts +253 -35
- package/src/plugins/builtin/chart-composer/index.tsx +12 -2
- package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
- package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
- package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
- package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
- package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
- package/src/plugins/builtin/chart-composer/settings.ts +31 -19
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
- package/src/plugins/builtin/chat/attachments/model.ts +3 -1
- package/src/plugins/builtin/chat/content/index.tsx +1 -1
- package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
- package/src/plugins/builtin/chat/people.ts +1 -1
- package/src/plugins/builtin/clinical-trials/client.ts +5 -2
- package/src/plugins/builtin/clinical-trials/model.ts +13 -4
- package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
- package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
- package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
- package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
- package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
- package/src/plugins/builtin/company-attention/building-model.ts +222 -0
- package/src/plugins/builtin/company-attention/building.tsx +172 -0
- package/src/plugins/builtin/company-attention/client.ts +117 -1
- package/src/plugins/builtin/company-attention/evidence.ts +16 -3
- package/src/plugins/builtin/company-attention/headless.ts +101 -5
- package/src/plugins/builtin/company-attention/index.tsx +6 -3
- package/src/plugins/builtin/company-attention/model.ts +33 -7
- package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
- package/src/plugins/builtin/company-attention/moves.tsx +159 -0
- package/src/plugins/builtin/company-attention/pane.tsx +89 -31
- package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
- package/src/plugins/builtin/company-attention/signals.tsx +160 -0
- package/src/plugins/builtin/company-kpis/headless.ts +3 -2
- package/src/plugins/builtin/company-kpis/model.ts +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/congress-trades/headless.ts +1 -1
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
- package/src/plugins/builtin/correlation/headless.ts +7 -4
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
- package/src/plugins/builtin/correlation/settings.ts +1 -0
- package/src/plugins/builtin/cot/headless.ts +28 -6
- package/src/plugins/builtin/cot/model.ts +12 -0
- package/src/plugins/builtin/cot/pane.tsx +7 -5
- package/src/plugins/builtin/cpi/headless.ts +5 -1
- package/src/plugins/builtin/cpi/pane.tsx +11 -9
- package/src/plugins/builtin/credit-boards/model.ts +2 -0
- package/src/plugins/builtin/credit-documents/headless.ts +1 -1
- package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
- package/src/plugins/builtin/crypto-board/client.ts +86 -0
- package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
- package/src/plugins/builtin/crypto-board/defi.ts +239 -0
- package/src/plugins/builtin/crypto-board/headless.ts +117 -6
- package/src/plugins/builtin/crypto-board/index.tsx +8 -3
- package/src/plugins/builtin/crypto-board/model.ts +40 -8
- package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
- package/src/plugins/builtin/crypto-board/series.ts +19 -1
- package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
- package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
- package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
- package/src/plugins/builtin/debug/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/docs/index.tsx +1 -1
- package/src/plugins/builtin/docs/pane.tsx +2 -2
- package/src/plugins/builtin/docs/targets.ts +1 -1
- package/src/plugins/builtin/doe/client.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +12 -6
- package/src/plugins/builtin/doe/model.ts +43 -6
- package/src/plugins/builtin/doe/pane.tsx +19 -12
- package/src/plugins/builtin/earnings/board-model.ts +13 -6
- package/src/plugins/builtin/earnings/board-table.ts +4 -1
- package/src/plugins/builtin/earnings/board.tsx +253 -50
- package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
- package/src/plugins/builtin/earnings/calendar.tsx +338 -0
- package/src/plugins/builtin/earnings/client.ts +4 -3
- package/src/plugins/builtin/earnings/headless.ts +53 -15
- package/src/plugins/builtin/earnings/history-model.ts +53 -36
- package/src/plugins/builtin/earnings/index.tsx +15 -22
- package/src/plugins/builtin/earnings/model.ts +17 -12
- package/src/plugins/builtin/earnings/scope.ts +89 -0
- package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
- package/src/plugins/builtin/earnings-calls/data.ts +146 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
- package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
- package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
- package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +132 -20
- package/src/plugins/builtin/econ/detail-view.tsx +48 -10
- package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
- package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
- package/src/plugins/builtin/econ/index.tsx +112 -25
- package/src/plugins/builtin/econ/print-watch.ts +2 -1
- package/src/plugins/builtin/econ/types.ts +32 -1
- package/src/plugins/builtin/econ-statistics/client.ts +16 -3
- package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
- package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
- package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
- package/src/plugins/builtin/econ-statistics/view.ts +16 -1
- package/src/plugins/builtin/equity-screener/client.ts +21 -3
- package/src/plugins/builtin/equity-screener/headless.ts +77 -5
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +34 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
- package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
- package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
- package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
- package/src/plugins/builtin/exposure/headless.ts +51 -6
- package/src/plugins/builtin/exposure/index.tsx +28 -2
- package/src/plugins/builtin/exposure/model.ts +7 -0
- package/src/plugins/builtin/exposure/pane.tsx +16 -10
- package/src/plugins/builtin/fear-greed/index.tsx +1 -1
- package/src/plugins/builtin/filing-events/index.tsx +1 -1
- package/src/plugins/builtin/futures/model.ts +10 -9
- package/src/plugins/builtin/futures/returns.ts +8 -36
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +40 -9
- package/src/plugins/builtin/futures-curve/headless.ts +39 -17
- package/src/plugins/builtin/futures-curve/model.ts +258 -69
- package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
- package/src/plugins/builtin/fx-matrix/client.ts +15 -8
- package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
- package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
- package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
- package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
- package/src/plugins/builtin/gpu/board.tsx +4 -1
- package/src/plugins/builtin/gpu/changes.tsx +10 -10
- package/src/plugins/builtin/gpu/equities.tsx +4 -1
- package/src/plugins/builtin/gpu/headless.ts +9 -4
- package/src/plugins/builtin/gpu/history.tsx +4 -2
- package/src/plugins/builtin/gpu/pane.tsx +5 -3
- package/src/plugins/builtin/help/index.tsx +13 -3
- package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
- package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +15 -2
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +48 -8
- package/src/plugins/builtin/holders/index-holders.ts +264 -0
- package/src/plugins/builtin/holders/pane.tsx +79 -15
- package/src/plugins/builtin/holders/report-rows.ts +35 -7
- package/src/plugins/builtin/holders/table-model.ts +2 -1
- package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
- package/src/plugins/builtin/holders/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/base-values.ts +11 -7
- package/src/plugins/builtin/insider/client.ts +3 -0
- package/src/plugins/builtin/insider/headless.ts +20 -7
- package/src/plugins/builtin/insider/index.tsx +17 -8
- package/src/plugins/builtin/insider/issuer.ts +34 -4
- package/src/plugins/builtin/insider/signals-client.ts +3 -3
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- package/src/plugins/builtin/insider/table-model.ts +35 -13
- package/src/plugins/builtin/insider/table.tsx +5 -2
- package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
- package/src/plugins/builtin/iv-history/client.ts +20 -0
- package/src/plugins/builtin/iv-history/events.ts +145 -0
- package/src/plugins/builtin/iv-history/format.ts +3 -0
- package/src/plugins/builtin/iv-history/headless.ts +91 -7
- package/src/plugins/builtin/iv-history/index.tsx +1 -1
- package/src/plugins/builtin/iv-history/model.ts +13 -4
- package/src/plugins/builtin/iv-history/series.ts +3 -1
- package/src/plugins/builtin/jobs/lock-note.ts +1 -1
- package/src/plugins/builtin/jobs/model.ts +4 -15
- package/src/plugins/builtin/jobs/pane.tsx +7 -5
- package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
- package/src/plugins/builtin/jodi/pane.tsx +14 -8
- package/src/plugins/builtin/layout-manager/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +20 -7
- package/src/plugins/builtin/macro-day/index.tsx +3 -2
- package/src/plugins/builtin/macro-day/model.ts +29 -8
- package/src/plugins/builtin/macro-day/pane.tsx +46 -10
- package/src/plugins/builtin/macro-day/releases.ts +55 -13
- package/src/plugins/builtin/market-heatmap/data.ts +9 -2
- package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
- package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
- package/src/plugins/builtin/market-heatmap/model.ts +10 -7
- package/src/plugins/builtin/market-movers/client.ts +36 -21
- package/src/plugins/builtin/market-movers/headless.ts +8 -2
- package/src/plugins/builtin/market-movers/index.tsx +16 -10
- package/src/plugins/builtin/market-movers/screener.ts +33 -11
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
- package/src/plugins/builtin/market-movers/session-table.ts +4 -2
- package/src/plugins/builtin/market-movers/table.ts +4 -1
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/view.ts +5 -0
- package/src/plugins/builtin/members/headless.ts +6 -5
- package/src/plugins/builtin/members/pane.tsx +11 -4
- package/src/plugins/builtin/mna/client.ts +1 -0
- package/src/plugins/builtin/mna/detail.tsx +20 -32
- package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
- package/src/plugins/builtin/mna/distress/model.ts +3 -2
- package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
- package/src/plugins/builtin/mna/headless.ts +6 -13
- package/src/plugins/builtin/mna/model.ts +93 -15
- package/src/plugins/builtin/mna/pane.tsx +5 -4
- package/src/plugins/builtin/news/headless.ts +12 -6
- package/src/plugins/builtin/news/index.tsx +10 -1
- package/src/plugins/builtin/news/wire/index.tsx +3 -2
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
- package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
- package/src/plugins/builtin/notes/cli.ts +50 -15
- package/src/plugins/builtin/notes/export.ts +17 -6
- package/src/plugins/builtin/notes/files.ts +16 -5
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/enrichment-model.ts +10 -9
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/model-spot.ts +70 -4
- package/src/plugins/builtin/options/view.tsx +51 -23
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
- package/src/plugins/builtin/options-positioning/headless.ts +11 -3
- package/src/plugins/builtin/options-positioning/model.ts +24 -0
- package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
- package/src/plugins/builtin/options-scenario/client.ts +142 -29
- package/src/plugins/builtin/options-scenario/collar.ts +8 -6
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
- package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
- package/src/plugins/builtin/options-scenario/csp.ts +101 -21
- package/src/plugins/builtin/options-scenario/headless.ts +49 -21
- package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
- package/src/plugins/builtin/options-scenario/index.tsx +28 -3
- package/src/plugins/builtin/options-scenario/model.ts +13 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
- package/src/plugins/builtin/perps/equity-row.tsx +11 -3
- package/src/plugins/builtin/perps/freshness.ts +8 -5
- package/src/plugins/builtin/perps/headless.ts +3 -1
- package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
- package/src/plugins/builtin/perps/live-rows.ts +161 -0
- package/src/plugins/builtin/perps/markets-section.tsx +154 -0
- package/src/plugins/builtin/perps/pane.tsx +36 -17
- package/src/plugins/builtin/perps/venue-markets.ts +96 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
- package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
- package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
- package/src/plugins/builtin/portfolio-list/income.ts +13 -2
- package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
- package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
- package/src/plugins/builtin/power/client.ts +6 -3
- package/src/plugins/builtin/power/evidence.ts +22 -7
- package/src/plugins/builtin/power/gas.tsx +5 -1
- package/src/plugins/builtin/power/pane.tsx +44 -32
- package/src/plugins/builtin/power/prices.tsx +10 -3
- package/src/plugins/builtin/research/analyst-headless.ts +25 -8
- package/src/plugins/builtin/research/analyst-model.ts +68 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
- package/src/plugins/builtin/research/event-model.ts +3 -1
- package/src/plugins/builtin/research/event-sources.ts +12 -4
- package/src/plugins/builtin/research/index.tsx +2 -1
- package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
- package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
- package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
- package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -1
- package/src/plugins/builtin/seasonality/client.ts +2 -1
- package/src/plugins/builtin/sec/forms.ts +13 -0
- package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
- package/src/plugins/builtin/sec/fund-facts.ts +68 -8
- package/src/plugins/builtin/sec/headless.ts +85 -8
- package/src/plugins/builtin/sec/index.tsx +58 -12
- package/src/plugins/builtin/sectors/client.ts +6 -4
- package/src/plugins/builtin/sectors/sector-model.ts +11 -15
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
- package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
- package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
- package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
- package/src/plugins/builtin/shared/earnings-report.ts +3 -3
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
- package/src/plugins/builtin/shared/job-posting.ts +129 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
- package/src/plugins/builtin/shared/report-freshness.ts +3 -0
- package/src/plugins/builtin/shared/research-trading.tsx +23 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
- package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
- package/src/plugins/builtin/shared/volatility/options.ts +2 -1
- package/src/plugins/builtin/short-interest/client.ts +2 -0
- package/src/plugins/builtin/short-interest/headless.ts +41 -12
- package/src/plugins/builtin/short-interest/index.tsx +23 -1
- package/src/plugins/builtin/short-interest/model.ts +70 -19
- package/src/plugins/builtin/short-interest/pane.tsx +19 -2
- package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
- package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
- package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
- package/src/plugins/builtin/short-interest/schedule.ts +35 -2
- package/src/plugins/builtin/short-interest/surface.tsx +11 -4
- package/src/plugins/builtin/short-interest/types.ts +9 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
- package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
- package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
- package/src/plugins/builtin/social-mentions/client.ts +2 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
- package/src/plugins/builtin/supply-chain/model.ts +51 -3
- package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -5
- package/src/plugins/builtin/themes/model.ts +14 -4
- package/src/plugins/builtin/themes/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/headless.ts +5 -5
- package/src/plugins/builtin/thirteenf/signals.ts +3 -1
- package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
- package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
- package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
- package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
- package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
- package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
- package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
- package/src/plugins/builtin/vol-surface/client.ts +28 -7
- package/src/plugins/builtin/vol-surface/headless.ts +43 -15
- package/src/plugins/builtin/vol-surface/model.ts +34 -12
- package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
- package/src/plugins/builtin/vol-surface/stored.ts +34 -3
- package/src/plugins/builtin/vol-surface/tables.ts +14 -0
- package/src/plugins/builtin/volatility/model.ts +5 -10
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
- package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
- package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
- package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -26
- package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
- package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
- package/src/plugins/builtin/yield-curve/client.ts +25 -0
- package/src/plugins/builtin/yield-curve/curves.ts +7 -4
- package/src/plugins/builtin/yield-curve/headless.ts +38 -4
- package/src/plugins/builtin/yield-curve/history.ts +4 -3
- package/src/plugins/builtin/yield-curve/index.tsx +12 -6
- package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
- package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
- package/src/plugins/bundle.ts +1 -1
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/compat.ts +3 -3
- package/src/plugins/dependencies.ts +75 -14
- package/src/plugins/extracted-plugins.ts +132 -34
- package/src/plugins/host-link.ts +149 -34
- package/src/plugins/installer.ts +35 -10
- package/src/plugins/loader.ts +206 -38
- package/src/plugins/manager-node.ts +2 -2
- package/src/plugins/marketplace/deactivation.ts +22 -0
- package/src/plugins/marketplace/model.ts +2 -2
- package/src/plugins/marketplace/packs.ts +1 -1
- package/src/plugins/ownership.ts +1 -1
- package/src/plugins/peer-retry.ts +155 -0
- package/src/plugins/registry/contributions.ts +3 -1
- package/src/plugins/registry/index.ts +4 -3
- package/src/plugins/registry/plugin-state.ts +3 -0
- package/src/plugins/seed-notice.ts +20 -0
- package/src/plugins/shortcut-argument.ts +39 -0
- package/src/portfolio/allocation.ts +1 -1
- package/src/portfolio/collection-name.ts +31 -0
- package/src/portfolio/column-values.ts +10 -8
- package/src/portfolio/cost-fx.ts +296 -19
- package/src/portfolio/manual-lots.ts +75 -0
- package/src/portfolio/mutations.ts +60 -22
- package/src/portfolio/suffixed-listings.ts +209 -0
- package/src/portfolio/totals-currency.ts +24 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
- package/src/public/time-series.ts +11 -8
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/config-host.ts +3 -0
- package/src/renderers/browser/main.tsx +23 -3
- package/src/renderers/dom/boot-frame-page.ts +187 -0
- package/src/renderers/dom/boot-frame.ts +237 -0
- package/src/renderers/dom/build-assets.ts +46 -8
- package/src/renderers/dom/desktop/controls.tsx +1 -1
- package/src/renderers/dom/desktop/query-bar.tsx +2 -0
- package/src/renderers/dom/dom-ui-host.tsx +4 -29
- package/src/renderers/dom/host/ascii-text.ts +16 -2
- package/src/renderers/dom/host/box.tsx +43 -2
- package/src/renderers/dom/host/chart-surface.tsx +2 -0
- package/src/renderers/dom/host/hls.chunk.ts +3 -0
- package/src/renderers/dom/host/image-surface.tsx +49 -0
- package/src/renderers/dom/host/media-surface.tsx +24 -18
- package/src/renderers/dom/host/mouse.ts +30 -0
- package/src/renderers/dom/host/size-observer.ts +1 -1
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/host/tabs.tsx +16 -5
- package/src/renderers/dom/host/top-surface.ts +127 -0
- package/src/renderers/dom/styles.css +115 -0
- package/src/renderers/dom/test-utils.tsx +2 -1
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
- package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
- package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
- package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
- package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
- package/src/renderers/electrobun/bun/index.ts +11 -1
- package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -1
- package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
- package/src/renderers/electrobun/shared/protocol.ts +6 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/config-host.ts +3 -0
- package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
- package/src/renderers/electrobun/view/main.tsx +30 -4
- package/src/renderers/electrobun/view/news-source.ts +9 -7
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
- package/src/renderers/electrobun/view/ui-host.tsx +1 -1
- package/src/renderers/opentui/browser-open.ts +88 -0
- package/src/renderers/opentui/host.tsx +5 -14
- package/src/renderers/opentui/image/loader.ts +3 -2
- package/src/renderers/opentui/native-smoke.ts +10 -1
- package/src/renderers/opentui/pane-image/index.ts +2 -1
- package/src/renderers/opentui/render-lib.ts +253 -0
- package/src/renderers/opentui/render-timing-smoke.ts +1 -1
- package/src/renderers/opentui/start.tsx +8 -1
- package/src/renderers/share/layout-view.tsx +2 -2
- package/src/renderers/share/main.tsx +4 -4
- package/src/renderers/share/view.tsx +1 -1
- package/src/series/resolve.ts +22 -6
- package/src/series/standalone.ts +30 -2
- package/src/series/types.ts +8 -1
- package/src/shares/api.ts +4 -1
- package/src/shares/pane.ts +1 -1
- package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
- package/src/sources/gloomberb-cloud/index.ts +39 -16
- package/src/sources/gloomberb-cloud/news.ts +39 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
- package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
- package/src/sources/listing-symbols.ts +37 -0
- package/src/sources/provider-errors.ts +16 -2
- package/src/sources/provider-router/financial-routes.ts +21 -3
- package/src/sources/provider-router/financials.ts +15 -2
- package/src/sources/provider-router/history.ts +30 -8
- package/src/sources/provider-router/index.ts +16 -0
- package/src/sources/provider-router/primary.ts +1 -1
- package/src/state/app/bootstrap.ts +23 -0
- package/src/state/hooks/inline-tickers.ts +30 -5
- package/src/sync/controller.ts +1 -1
- package/src/sync/core-contributors.ts +46 -14
- package/src/team/collections-sync.ts +2 -1
- package/src/team/collections.ts +178 -17
- package/src/telemetry/crash-reports.ts +21 -4
- package/src/telemetry/update-failures-node.ts +59 -0
- package/src/telemetry/update-failures.ts +307 -0
- package/src/test-support/builtin-panes.ts +1 -1
- package/src/theme/colors.ts +3 -30
- package/src/theme/ui-tokens.ts +37 -1
- package/src/tickers/company-name-listing.ts +215 -36
- package/src/tickers/company-name.ts +43 -0
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- package/src/tickers/listing-fate.ts +30 -0
- package/src/tickers/metadata.ts +10 -0
- package/src/tickers/perpetual-listing.ts +5 -2
- package/src/tickers/search/home-listing.ts +75 -0
- package/src/tickers/search/index.ts +76 -27
- package/src/tickers/search/ranking.ts +54 -4
- package/src/tickers/search/upsert.ts +29 -0
- package/src/tickers/terminal-codes.ts +416 -40
- package/src/time-series/bar-aggregation.ts +243 -0
- package/src/time-series/base-series.ts +307 -0
- package/src/time-series/chart-bounds.ts +349 -0
- package/src/time-series/chart-seed.ts +142 -0
- package/src/time-series/economic.ts +5 -0
- package/src/time-series/fundamentals.ts +18 -3
- package/src/time-series/history-acquisition.ts +499 -0
- package/src/time-series/leverage.ts +100 -0
- package/src/time-series/market-resolution.ts +4 -2
- package/src/time-series/market.ts +2 -1
- package/src/time-series/price-comparison.ts +175 -30
- package/src/time-series/range.ts +9 -1
- package/src/time-series/resolution.ts +174 -16
- package/src/time-series/resolve-context.ts +157 -0
- package/src/time-series/resolve.ts +126 -1577
- package/src/time-series/series-name.ts +38 -0
- package/src/time-series/series-presentation.ts +208 -0
- package/src/time-series/spec.ts +11 -6
- package/src/time-series/studies.ts +109 -12
- package/src/time-series/tail-reconcile.ts +121 -0
- package/src/time-series/types.ts +29 -2
- package/src/time-series/use-chart-resolution.ts +4 -5
- package/src/types/broker.ts +10 -0
- package/src/types/config.ts +14 -0
- package/src/types/data-provider.ts +20 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +83 -6
- package/src/types/instrument.ts +3 -0
- package/src/types/issuer-listings.ts +28 -0
- package/src/types/plugin.ts +65 -8
- package/src/types/price-history.ts +2 -0
- package/src/types/ticker.ts +13 -0
- package/src/types/trading.ts +59 -1
- package/src/ui/ascii-font.ts +13 -1
- package/src/ui/host.tsx +6 -1
- package/src/updater/command-names.ts +175 -0
- package/src/updater/failure.ts +163 -0
- package/src/updater/index.ts +97 -28
- package/src/utils/calendar-date.ts +32 -15
- package/src/utils/cash-runway.ts +241 -0
- package/src/utils/central-banks.ts +42 -0
- package/src/utils/cli-output.ts +259 -80
- package/src/utils/contract-month.ts +16 -0
- package/src/utils/crypto-pair.ts +61 -3
- package/src/utils/currency-pair.ts +26 -0
- package/src/utils/currency-units.ts +29 -0
- package/src/utils/datetime-format.ts +10 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/decimal-comma.ts +39 -6
- package/src/utils/exchange-announcements.ts +71 -0
- package/src/utils/exchange-rate-snapshot.ts +10 -0
- package/src/utils/financial-statements.ts +83 -4
- package/src/utils/format.ts +34 -16
- package/src/utils/fundamentals.ts +150 -34
- package/src/utils/fx-market-hours.ts +10 -1
- package/src/utils/latest-financial-period.ts +8 -0
- package/src/utils/linux-libc.ts +54 -0
- package/src/utils/market-capitalization.ts +111 -15
- package/src/utils/max-drawdown.ts +64 -0
- package/src/utils/network-failure.ts +83 -0
- package/src/utils/option-expiry.ts +139 -7
- package/src/utils/price-earnings.ts +11 -5
- package/src/utils/price-history.ts +18 -8
- package/src/utils/price-window.ts +131 -0
- package/src/utils/release-date.ts +47 -0
- package/src/utils/sec.ts +71 -0
- package/src/utils/throttled-fetch.ts +11 -4
- package/src/utils/trailing-eps.ts +67 -0
- package/src/utils/typed-text.ts +21 -0
- package/src/utils/utc-time.ts +24 -1
- package/src/version.ts +6 -0
- package/src/cli/pane-functions/screenshot.ts +0 -2122
|
@@ -4,8 +4,8 @@ import type { HeadlessPaneColumn, HeadlessPaneDefinition, HeadlessPaneEntry, Hea
|
|
|
4
4
|
import { formatPercentRaw } from "../../../utils/format";
|
|
5
5
|
import { DATE_OPTION_EXAMPLES } from "../../../utils/calendar-date";
|
|
6
6
|
import { newestReportTime, oldestReportTime } from "../../../utils/utc-time";
|
|
7
|
-
import { fetchFuturesCurve, loadCurveSpot, loadFuturesCurveAsOf } from "./client";
|
|
8
|
-
import { basisSpotSymbol, BASIS_CONVENTION, blankBasisNote, catalogueCurveUnit, curveAsOfDate, curveBasisPercent, curveBasisRows, curveChangeText, curveContractCode, curvePrice, curveRoundedPrice,
|
|
7
|
+
import { fetchFuturesCurve, loadCurveSpot, loadCurveSpotBars, loadFuturesCurveAsOf } from "./client";
|
|
8
|
+
import { basisSpotSymbol, BASIS_CONVENTION, blankBasisNote, catalogueCurveUnit, curveAsOfDate, curveBasisPercent, curveBasisRows, curveChangeText, curveContractCode, curvePrice, curveRoundedPrice, curveSpotSource, curveSpreadLabel, curveTimestamp, curveNoTradeSince, curveUnitLabel, noTradeChangeNote, normalizeCurveRoot, shortDatedBasisNote, thinSpreadNotice, unpairedContractCount, unsupportedCurveRootMessage, type ContractBasis } from "./model";
|
|
9
9
|
import { COMMODITIES_VIEW_STATE } from "../commodities-energy/view-state";
|
|
10
10
|
|
|
11
11
|
/** The root a report shows when none is given. */
|
|
@@ -22,6 +22,11 @@ const basisValue = (value: number | null) => value == null ? null : Number(value
|
|
|
22
22
|
* every root. Prices and changes are at the root's tick precision. `price` is
|
|
23
23
|
* the latest trade and `settlement` the exchange settlement for the curve's
|
|
24
24
|
* settlement session (a past curve's settled rows have no separate trade).
|
|
25
|
+
* `change` is `price` less `settlement`; `noTradeSince` dates the settlement
|
|
26
|
+
* a contract has not traded since, whose change is therefore blank. A crypto
|
|
27
|
+
* root adds the basis: the spot in the minute of `price`'s trade and that
|
|
28
|
+
* minute (`spot`, `spotTime`), the fractional days from the trade to final
|
|
29
|
+
* settlement, and the premium and its yearly rate.
|
|
25
30
|
*/
|
|
26
31
|
function contractRow(row: FuturesContract, data: FuturesCurvePayload, root: string, past: boolean, basis?: ContractBasis) {
|
|
27
32
|
const price = (value: number | null | undefined) => curveRoundedPrice(value, root);
|
|
@@ -30,15 +35,21 @@ function contractRow(row: FuturesContract, data: FuturesCurvePayload, root: stri
|
|
|
30
35
|
firstNotice: row.firstNotice ?? null, inDelivery: row.inDelivery ?? false,
|
|
31
36
|
settlement: price(row.settlement), settlementDate: row.settlement != null ? data.settlementDate ?? null : null,
|
|
32
37
|
price: past && row.settlement != null ? null : price(row.price), change: price(row.change),
|
|
38
|
+
noTradeSince: past ? null : curveNoTradeSince(row, data),
|
|
33
39
|
asOf: row.asOf, stale: row.stale, volume: row.volume, openInterest: row.openInterest, percentile: rank(row.percentile),
|
|
34
40
|
samples: row.samples, historyStart: row.historyStart, historyEnd: row.historyEnd,
|
|
35
41
|
currency: row.currency, quoteUnit: curveUnitLabel(data) ?? row.quoteUnit, delayMinutes: row.delayMinutes,
|
|
36
|
-
...(basis ? {
|
|
42
|
+
...(basis ? { spot: price(basis.spot), spotTime: basis.spotTime, daysToExpiry: basisValue(basis.daysToExpiry),
|
|
43
|
+
vsSpotPct: basisValue(basis.vsSpotPct), annualisedBasisPct: basisValue(basis.annualisedBasisPct) } : {}),
|
|
37
44
|
};
|
|
38
45
|
}
|
|
39
46
|
|
|
40
|
-
/**
|
|
41
|
-
|
|
47
|
+
/**
|
|
48
|
+
* The table: what a hedge reads, in one order for every root; JSON keeps every
|
|
49
|
+
* field. A crypto root's spot is the one each trade is read against; the
|
|
50
|
+
* export dates it, where the text leaves its minute to As Of UTC, the trade's.
|
|
51
|
+
*/
|
|
52
|
+
function contractColumns(root: string, settlementDate: string | null, options: { basis: boolean; last: boolean; notice: boolean; text?: boolean }): HeadlessPaneColumn[] {
|
|
42
53
|
const price = (value: unknown) => typeof value === "number" ? curvePrice(value, root) : "--";
|
|
43
54
|
const date = (value: unknown) => typeof value === "string" ? value : "--";
|
|
44
55
|
return [
|
|
@@ -51,7 +62,10 @@ function contractColumns(root: string, settlementDate: string | null, options: {
|
|
|
51
62
|
// A Cboe price is the settlement itself, with no separate last trade.
|
|
52
63
|
...options.last ? [{ key: "price", header: "Last", align: "right" as const, format: price }] : [],
|
|
53
64
|
{ key: "change", header: "Change", align: "right", format: (value) => typeof value === "number" ? curveChangeText(value, root) : "--" },
|
|
54
|
-
...options.basis ? [{ key: "
|
|
65
|
+
...options.basis ? [{ key: "spot", header: "Spot", align: "right" as const, format: price },
|
|
66
|
+
...options.text ? [] : [{ key: "spotTime", header: "Spot Time UTC", shrink: false, format: (value: unknown) => typeof value === "string" ? curveTimestamp(value) : "--" }],
|
|
67
|
+
{ key: "vsSpotPct", header: "Vs Spot", align: "right" as const, format: (value: unknown) => curveBasisPercent(typeof value === "number" ? value : null, 2) },
|
|
68
|
+
{ key: "daysToExpiry", header: "Days to Expiry", textHeader: "Days", align: "right" as const, format: (value: unknown) => typeof value === "number" ? value.toFixed(1) : "--" },
|
|
55
69
|
{ key: "annualisedBasisPct", header: "Ann Basis", align: "right" as const, format: (value: unknown) => curveBasisPercent(typeof value === "number" ? value : null, 1) }] : [],
|
|
56
70
|
{ key: "asOf", header: "As Of UTC", shrink: false, format: (value) => typeof value === "string" ? curveTimestamp(value) : "--" },
|
|
57
71
|
{ key: "openInterest", header: "Open Int", align: "right", format: (value) => typeof value === "number" ? value.toLocaleString("en-US") : "--" },
|
|
@@ -70,8 +84,9 @@ function fieldColumns(order: readonly string[], fields: object, formats: Record<
|
|
|
70
84
|
.map((key) => ({ key, header: key, ...formats[key] ? { textFormat: formats[key] } : {} }));
|
|
71
85
|
}
|
|
72
86
|
|
|
87
|
+
// `basis` says which prices the value subtracts: two last trades made together, or the settlements of the session in `asOf`.
|
|
73
88
|
const FRONT_SPREAD_FIELDS = ["label", "frontSymbol", "nextSymbol", "value", "annualizedRollYield", "percentile", "rollPercentile",
|
|
74
|
-
"samples", "historyStart", "historyEnd", "asOf", "state"];
|
|
89
|
+
"samples", "historyStart", "historyEnd", "asOf", "basis", "state", "thinSymbol"];
|
|
75
90
|
const GHOST_FIELDS = ["symbol", "expiration", "price", "asOf"];
|
|
76
91
|
/** The annualized roll yield reads as the percent it is (+32.36%); an export keeps the number. */
|
|
77
92
|
const ROLL_YIELD_FORMAT = { annualizedRollYield: (value: unknown) => typeof value === "number" ? formatPercentRaw(value) : "--" };
|
|
@@ -93,7 +108,7 @@ function specEntries(data: FuturesCurvePayload): HeadlessPaneEntry[] {
|
|
|
93
108
|
export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
94
109
|
discovery: { aliases: ["CTM"], dataRequirements: ["Gloom Cloud futures curve endpoint"],
|
|
95
110
|
limitations: ["Listed-contract catalogues can be incomplete.", "Ghosts and percentiles use the same listed contracts.", "Cboe VIX is daily settlement.",
|
|
96
|
-
"Ann Basis is simple actual/365
|
|
111
|
+
"Ann Basis is simple actual/365, each last trade against spot in the same minute, and noisy under 7 days to expiry."],
|
|
97
112
|
intents: ["futures basis trade", "cash and carry", "basis against spot"] },
|
|
98
113
|
shape: "bundle", argument: { kind: "free-text", optional: true, placeholder: "root", description: "FUT root such as CL, ES, ZN or VX, or a CME crypto root (BTC, ETH, SOL, XRP). Defaults to ES." },
|
|
99
114
|
// Only the pane reads the tab; the report always carries both.
|
|
@@ -106,23 +121,30 @@ export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
106
121
|
const input = args.argument || DEFAULT_ROOT;
|
|
107
122
|
const root = normalizeCurveRoot(input);
|
|
108
123
|
if (!root) throw new Error(unsupportedCurveRootMessage(input));
|
|
109
|
-
const date = curveAsOfDate(args.options.date);
|
|
124
|
+
const date = curveAsOfDate(args.options.date, new Date(), "--date");
|
|
110
125
|
// The archive keeps no spot history, so a past curve has no basis.
|
|
111
126
|
const spotSymbol = date ? null : basisSpotSymbol(root);
|
|
112
127
|
const now = Date.now();
|
|
113
|
-
|
|
128
|
+
// The quote names the spot and its feed; the one-minute bars price each trade's own minute.
|
|
129
|
+
const [data, spot, bars] = await Promise.all([
|
|
114
130
|
date ? loadFuturesCurveAsOf(root, date, ctx.apiClient) : fetchFuturesCurve(root, ctx.apiClient),
|
|
115
131
|
spotSymbol ? loadCurveSpot(spotSymbol, ctx.marketData, now) : null,
|
|
132
|
+
spotSymbol ? loadCurveSpotBars(spotSymbol, ctx.marketData, ctx.refresh === true) : null,
|
|
116
133
|
]);
|
|
117
|
-
const bases = spot ? curveBasisRows(data.contracts,
|
|
134
|
+
const bases = spot && bars ? curveBasisRows(data.contracts, bars) : null;
|
|
118
135
|
const unit = curveUnitLabel(data);
|
|
119
136
|
const terms = specEntries(data);
|
|
120
137
|
const source = spot ? curveSpotSource(spot) : null;
|
|
121
138
|
const notices = [...args.argument ? [] : [`Showing ${DEFAULT_ROOT}. Try fn CTM ${EXAMPLE_ROOT}.`],
|
|
122
|
-
...spot ? [
|
|
139
|
+
...spot ? [`Basis against ${spot.symbol} spot in each last trade's own minute${source ? ` (${source})` : ""}; not the CME reference rate.`] : []];
|
|
123
140
|
// The footnotes under the table: the convention, why a cell is blank, and where a short-dated rate is not to be trusted.
|
|
124
|
-
|
|
125
|
-
|
|
141
|
+
const basisNotes = bases ? [BASIS_CONVENTION, blankBasisNote(data.contracts, bases), shortDatedBasisNote(data.contracts, bases)]
|
|
142
|
+
.filter((note): note is string => !!note) : [];
|
|
143
|
+
// A blank Change says why, as a blank basis does; a past curve has no session change to blank.
|
|
144
|
+
const changeNote = date ? null : noTradeChangeNote(data.contracts, data);
|
|
145
|
+
const thinSpread = thinSpreadNotice(data);
|
|
146
|
+
const notes = [...thinSpread ? [`${thinSpread}.`] : [], ...changeNote ? [changeNote] : [], ...basisNotes];
|
|
147
|
+
const columnOptions = { basis: !!bases, last: data.source !== "cboe", notice: data.contracts.some((row) => row.firstNotice) };
|
|
126
148
|
// Dated by the contracts' own quotes; the same-contract history rows are a year of context, not observations.
|
|
127
149
|
const quoted = data.contracts.map((row) => row.asOf);
|
|
128
150
|
const freshness: HeadlessPaneFreshness = date
|
|
@@ -132,8 +154,8 @@ export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
132
154
|
return {
|
|
133
155
|
freshness,
|
|
134
156
|
sections: [
|
|
135
|
-
{ title: "Contracts", columns: contractColumns(root, data.settlementDate ?? null,
|
|
136
|
-
{
|
|
157
|
+
{ title: "Contracts", columns: contractColumns(root, data.settlementDate ?? null, columnOptions),
|
|
158
|
+
...bases ? { textColumns: contractColumns(root, data.settlementDate ?? null, { ...columnOptions, text: true }) } : {},
|
|
137
159
|
rows: data.contracts.map((row) => contractRow(row, data, root, !!date, bases?.get(row.symbol))) },
|
|
138
160
|
{ title: "Front spread", columns: fieldColumns(FRONT_SPREAD_FIELDS, data.slope, ROLL_YIELD_FORMAT), rows: [{ label: curveSpreadLabel(data.slope), ...data.slope, value: curveRoundedPrice(data.slope.value, root),
|
|
139
161
|
annualizedRollYield: data.slope.annualizedRollYield == null ? null : Number(data.slope.annualizedRollYield.toFixed(2)),
|
|
@@ -144,7 +166,7 @@ export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
144
166
|
],
|
|
145
167
|
errors: data.gaps,
|
|
146
168
|
...(notes.length ? { notes } : {}),
|
|
147
|
-
metadata: { ...data, quoteUnit: unit, ...(spot && bases ? { spot,
|
|
169
|
+
metadata: { ...data, quoteUnit: unit, ...(spot && bases ? { spot, basisBlankedUnpaired: unpairedContractCount(bases.values()) } : {}), ...(args.argument ? {} : { defaultArgument: DEFAULT_ROOT }),
|
|
148
170
|
...(notices.length ? { notices } : {}),
|
|
149
171
|
complete: data.status === "available", percentileBasis: "Same-contract observations within one year; actual sample start/end retained" },
|
|
150
172
|
};
|
|
@@ -4,10 +4,12 @@ import { spanDigits } from "../../../components/chart-table";
|
|
|
4
4
|
import { compositeAxisTicks } from "../../../components/chart/composite/format";
|
|
5
5
|
import type { CompositeAxisDomain } from "../../../components/chart/composite/types";
|
|
6
6
|
import { FUTURES_CONTRACTS, futuresBoardContractForTicker, futuresContractByCode, tickDecimals } from "../../../market-data/futures-board";
|
|
7
|
+
import { contractMonthLabel } from "../../../utils/contract-month";
|
|
7
8
|
import { formatPercentileRank } from "../../../utils/format";
|
|
8
9
|
import { cryptoPairCoin, isFuturesSymbol } from "../shared/crypto-pair";
|
|
9
10
|
import { parseReportTime } from "../../../utils/utc-time";
|
|
10
|
-
import {
|
|
11
|
+
import { zonedWallClockToUtcMs } from "../../../utils/zoned-date-time";
|
|
12
|
+
import { dateOptionError, dateOptionFormatsOr, readCalendarDate } from "../../../utils/calendar-date";
|
|
11
13
|
import { compareSortValues, type SortDirection } from "../../../utils/sort-values";
|
|
12
14
|
|
|
13
15
|
/**
|
|
@@ -147,6 +149,41 @@ export function curveSpreadLabel(slope: Pick<FuturesCurvePayload["slope"], "fron
|
|
|
147
149
|
return slope.frontSymbol && slope.nextSymbol ? `${curveContractCode(slope.nextSymbol)}-${curveContractCode(slope.frontSymbol)}` : "M2-M1";
|
|
148
150
|
}
|
|
149
151
|
|
|
152
|
+
/** A leg that traded fewer lots than this in its session is too thin to call a curve's slope from. */
|
|
153
|
+
const THIN_SPREAD_LOTS = 20;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* What the front spread subtracts, as its figure says it: "settle 10-22" for
|
|
157
|
+
* two settlements of a session (the Settle column's date), "last 20:59" for
|
|
158
|
+
* two last trades made together, dated when not the newest quote's day. Null
|
|
159
|
+
* when the server does not say.
|
|
160
|
+
*/
|
|
161
|
+
export function curveSpreadBasis(slope: Pick<FuturesCurvePayload["slope"], "basis" | "asOf">, newest: string | null): string | null {
|
|
162
|
+
if (!slope.basis || !slope.asOf) return null;
|
|
163
|
+
if (slope.basis === "settle" || !slope.asOf.includes("T")) return `${slope.basis} ${slope.asOf.slice(5, 10)}`;
|
|
164
|
+
const stamp = curveTimestamp(slope.asOf);
|
|
165
|
+
return `last ${newest?.includes("T") && curveTimestamp(newest).slice(0, 10) === stamp.slice(0, 10) ? stamp.slice(11) : stamp.slice(5)}`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Why the front spread is thin, from its thin leg's row: "ALIX26 traded 4 lots"
|
|
170
|
+
* or "ALIX26 last traded 2026-10-22". Null when it is not thin.
|
|
171
|
+
*/
|
|
172
|
+
function thinSpreadReason(data: Pick<FuturesCurvePayload, "slope" | "contracts">): string | null {
|
|
173
|
+
if (data.slope.state !== "thin") return null;
|
|
174
|
+
const leg = data.contracts.find((row) => row.symbol === data.slope.thinSymbol);
|
|
175
|
+
if (!leg) return null;
|
|
176
|
+
const code = curveContractCode(leg.symbol);
|
|
177
|
+
if (leg.volume != null && leg.volume < THIN_SPREAD_LOTS) return `${code} traded ${leg.volume} lot${leg.volume === 1 ? "" : "s"}`;
|
|
178
|
+
return leg.asOf ? `${code} last traded ${leg.asOf.slice(0, 10)}` : `${code} has not traded`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** The warning a thin front spread carries: why, and that its sign is no slope call. */
|
|
182
|
+
export function thinSpreadNotice(data: Pick<FuturesCurvePayload, "slope" | "contracts">): string | null {
|
|
183
|
+
const reason = thinSpreadReason(data);
|
|
184
|
+
return reason ? `${curveSpreadLabel(data.slope)} is thin (${reason}): no contango or backwardation call` : null;
|
|
185
|
+
}
|
|
186
|
+
|
|
150
187
|
/**
|
|
151
188
|
* Axis gridlines sit on round values, so they need no tick precision: one
|
|
152
189
|
* decimal count across the gutter, as many as the plotted range asks for and
|
|
@@ -166,17 +203,16 @@ export function curveAxisPrice(value: number, domain: CompositeAxisDomain, root:
|
|
|
166
203
|
}
|
|
167
204
|
|
|
168
205
|
const MONTH_CODES = "FGHJKMNQUVXZ";
|
|
169
|
-
const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
170
206
|
|
|
171
207
|
/**
|
|
172
|
-
* The delivery month a trader names a contract by ("Nov
|
|
208
|
+
* The delivery month a trader names a contract by ("Nov 2026" for CLX26), not
|
|
173
209
|
* its last trading day: crude's November contract expires in October, and a
|
|
174
210
|
* "26-10-20" label also reads as a day-first date.
|
|
175
211
|
*/
|
|
176
212
|
export function curveContractMonth(symbol: string, expiration: string): string {
|
|
177
213
|
const coded = /^[A-Z0-9]+?([FGHJKMNQUVXZ])(\d{2})\.[A-Z]+$/.exec(symbol);
|
|
178
|
-
if (coded) return
|
|
179
|
-
return
|
|
214
|
+
if (coded) return contractMonthLabel(Number(coded[2]), MONTH_CODES.indexOf(coded[1]!));
|
|
215
|
+
return contractMonthLabel(Number(expiration.slice(0, 4)), Number(expiration.slice(5, 7)) - 1);
|
|
180
216
|
}
|
|
181
217
|
|
|
182
218
|
export function curveTimestamp(value: string | null): string {
|
|
@@ -288,7 +324,17 @@ const SPOT_STALE_MS = 10 * 60_000;
|
|
|
288
324
|
/** A free account's quote is held back on purpose; that delay is not staleness, so it is allowed on top. */
|
|
289
325
|
const DELAYED_SPOT_MS = 15 * 60_000;
|
|
290
326
|
|
|
291
|
-
/**
|
|
327
|
+
/**
|
|
328
|
+
* The listing codes the quote path reports for a spot, in plain words: a
|
|
329
|
+
* reader is told what the price is, never handed a bare code.
|
|
330
|
+
*/
|
|
331
|
+
const SPOT_VENUE_LABELS: Readonly<Record<string, string>> = { CCC: "crypto composite price" };
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* The latest spot quote, which the footer shows beside the curve, or why there
|
|
335
|
+
* is none. `asOf` is the quote's own time, never the fetch's. The basis does
|
|
336
|
+
* not read it: each contract is read against the spot in its own minute.
|
|
337
|
+
*/
|
|
292
338
|
export interface CurveSpot {
|
|
293
339
|
symbol: string;
|
|
294
340
|
price: number | null;
|
|
@@ -296,7 +342,7 @@ export interface CurveSpot {
|
|
|
296
342
|
asOf: string | null;
|
|
297
343
|
status: "ok" | "stale" | "missing";
|
|
298
344
|
reason: string | null;
|
|
299
|
-
/**
|
|
345
|
+
/** What the quote path reports the price is, in plain words (`crypto composite price`), when it reports it. */
|
|
300
346
|
venue?: string;
|
|
301
347
|
/** Whether the quote is real-time or held back, as the quote path reports it. */
|
|
302
348
|
feed?: "real-time" | "delayed";
|
|
@@ -324,7 +370,8 @@ function quoteAge(ms: number): string {
|
|
|
324
370
|
export function curveSpot(symbol: string, quote: SpotQuote | null | undefined, now: number): CurveSpot {
|
|
325
371
|
if (!quote || !positive(quote.price)) return { symbol, price: null, asOf: null, status: "missing", reason: `no ${symbol} quote` };
|
|
326
372
|
// What the quote path says about the quote itself, kept beside the price so the footer can name it.
|
|
327
|
-
const
|
|
373
|
+
const code = (quote.listingExchangeName || quote.exchangeName)?.trim();
|
|
374
|
+
const venue = code ? SPOT_VENUE_LABELS[code.toUpperCase()] ?? code : undefined;
|
|
328
375
|
const feed: CurveSpot["feed"] = quote.dataSource === "live" ? "real-time" : quote.dataSource === "delayed" ? "delayed" : undefined;
|
|
329
376
|
const source = { ...venue ? { venue } : {}, ...feed ? { feed } : {} };
|
|
330
377
|
const time = quote.lastUpdated;
|
|
@@ -339,54 +386,115 @@ export function curveSpot(symbol: string, quote: SpotQuote | null | undefined, n
|
|
|
339
386
|
return { symbol, price: quote.price, asOf, status: "ok", reason: null, ...source };
|
|
340
387
|
}
|
|
341
388
|
|
|
342
|
-
|
|
389
|
+
const MINUTE_MS = 60_000;
|
|
390
|
+
const minuteOf = (time: number) => Math.floor(time / MINUTE_MS) * MINUTE_MS;
|
|
391
|
+
const isoMinute = (time: number) => new Date(time).toISOString().replace(":00.000Z", ":00Z");
|
|
392
|
+
|
|
393
|
+
/** The spot in one UTC minute: the close of the spot pair's one-minute bar that opened then. */
|
|
394
|
+
export interface SpotBar {
|
|
395
|
+
/** Epoch milliseconds of the minute's start. */
|
|
396
|
+
minute: number;
|
|
397
|
+
price: number;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** One-minute bars as the spot by minute, oldest first; a bar with no usable time or close is left out. */
|
|
401
|
+
export function spotBarsFromHistory(points: readonly { date: Date | string | number; close: number }[]): SpotBar[] {
|
|
402
|
+
const byMinute = new Map<number, number>();
|
|
403
|
+
for (const point of points) {
|
|
404
|
+
const time = new Date(point.date).getTime();
|
|
405
|
+
if (Number.isFinite(time) && positive(point.close)) byMinute.set(minuteOf(time), point.close);
|
|
406
|
+
}
|
|
407
|
+
return [...byMinute].sort((a, b) => a[0] - b[0]).map(([minute, price]) => ({ minute, price }));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** The bar in `minute`, else the one nearest it; null when there are none. */
|
|
411
|
+
function nearestSpotBar(bars: readonly SpotBar[], minute: number): SpotBar | null {
|
|
412
|
+
let low = 0;
|
|
413
|
+
let high = bars.length - 1;
|
|
414
|
+
while (low <= high) {
|
|
415
|
+
const middle = (low + high) >> 1;
|
|
416
|
+
const bar = bars[middle]!;
|
|
417
|
+
if (bar.minute === minute) return bar;
|
|
418
|
+
if (bar.minute < minute) low = middle + 1;
|
|
419
|
+
else high = middle - 1;
|
|
420
|
+
}
|
|
421
|
+
const before = bars[high];
|
|
422
|
+
const after = bars[low];
|
|
423
|
+
if (!before) return after ?? null;
|
|
424
|
+
if (!after) return before;
|
|
425
|
+
return minute - before.minute <= after.minute - minute ? before : after;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/** How far a contract trades over (positive) or under spot, in percent. */
|
|
343
429
|
export function vsSpotPct(futures: number | null | undefined, spot: number | null | undefined): number | null {
|
|
344
430
|
return positive(futures) && positive(spot) ? (futures / spot - 1) * 100 : null;
|
|
345
431
|
}
|
|
346
432
|
|
|
347
|
-
/**
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
433
|
+
/**
|
|
434
|
+
* CME's crypto futures stop trading at 4:00 p.m. London time on their last
|
|
435
|
+
* trading day and settle to the CME CF reference rate published then, so a
|
|
436
|
+
* contract's days to expiry run to that instant, not to a calendar date.
|
|
437
|
+
*/
|
|
438
|
+
const FINAL_SETTLEMENT = { timeZone: "Europe/London", hour: 16 } as const;
|
|
439
|
+
|
|
440
|
+
/** The instant a crypto contract expiring on `expiration` (YYYY-MM-DD) settles, or null for a date that cannot be read. */
|
|
441
|
+
function finalSettlementTime(expiration: string): number | null {
|
|
442
|
+
const date = /^(\d{4})-(\d{2})-(\d{2})$/.exec(expiration);
|
|
443
|
+
if (!date) return null;
|
|
444
|
+
const time = zonedWallClockToUtcMs(FINAL_SETTLEMENT.timeZone, Number(date[1]), Number(date[2]), Number(date[3]), FINAL_SETTLEMENT.hour, 0, 0);
|
|
445
|
+
return Number.isFinite(time) ? time : null;
|
|
353
446
|
}
|
|
354
447
|
|
|
355
|
-
/**
|
|
448
|
+
/** Days, fractional, from `from` to the contract's final settlement: 6.6 from Saturday 01:33 UTC to Friday 16:00 London. */
|
|
449
|
+
export function daysToExpiry(from: number, expiration: string): number | null {
|
|
450
|
+
const settles = finalSettlementTime(expiration);
|
|
451
|
+
return settles == null || !Number.isFinite(from) ? null : (settles - from) / DAY_MS;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** The premium over spot as a yearly rate, on a 365-day year. Blank at or past final settlement, where it has no meaning. */
|
|
356
455
|
export function annualisedBasisPct(futures: number | null | undefined, spot: number | null | undefined, days: number | null): number | null {
|
|
357
456
|
if (!positive(futures) || !positive(spot) || days == null || !Number.isFinite(days) || days <= 0) return null;
|
|
358
457
|
return (futures / spot - 1) * 365 / days * 100;
|
|
359
458
|
}
|
|
360
459
|
|
|
361
|
-
/** A contract that printed longer than this before the spot quote is too old to read against it. */
|
|
362
|
-
const CONTRACT_PRINT_MAX_AGE_MS = 60 * 60_000;
|
|
363
|
-
|
|
364
460
|
export interface ContractBasis {
|
|
365
461
|
vsSpotPct: number | null;
|
|
366
462
|
annualisedBasisPct: number | null;
|
|
367
|
-
/**
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
463
|
+
/** The spot the last trade is read against: the close of the spot's bar in the trade's own minute. */
|
|
464
|
+
spot: number | null;
|
|
465
|
+
/** That bar's minute, as a UTC ISO instant. */
|
|
466
|
+
spotTime: string | null;
|
|
467
|
+
/** Fractional days from the last trade to the contract's final settlement. */
|
|
468
|
+
daysToExpiry: number | null;
|
|
469
|
+
/**
|
|
470
|
+
* Why a priced, current contract has no basis: its last trade has no time
|
|
471
|
+
* of day (`print` null), or no spot bar shares its minute, with the
|
|
472
|
+
* nearest bar's minute (null when there are no bars at all). Null when
|
|
473
|
+
* the contract has a basis or another rule blanks it.
|
|
474
|
+
*/
|
|
475
|
+
unpaired: { print: number | null; spot: number | null } | null;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const NO_BASIS: ContractBasis = { vsSpotPct: null, annualisedBasisPct: null, spot: null, spotTime: null, daysToExpiry: null, unpaired: null };
|
|
372
479
|
|
|
373
480
|
/**
|
|
374
|
-
* One contract's basis
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
* delayed feed trails the futures).
|
|
481
|
+
* One contract's basis: its last trade against the spot in the same UTC
|
|
482
|
+
* minute, so the two prices are never minutes apart, whichever is the newer
|
|
483
|
+
* (a delayed spot trails the futures, a live one leads them). Blank while
|
|
484
|
+
* the bars are unknown (`bars` null), for a contract whose own price is
|
|
485
|
+
* missing or stale, for a trade with no time of day, and for one no spot bar
|
|
486
|
+
* shares a minute with.
|
|
381
487
|
*/
|
|
382
|
-
export function contractBasis(row: Pick<FuturesContract, "price" | "stale" | "expiration" | "asOf">,
|
|
383
|
-
if (
|
|
384
|
-
const
|
|
385
|
-
if (
|
|
386
|
-
const
|
|
387
|
-
const
|
|
388
|
-
if (
|
|
389
|
-
|
|
488
|
+
export function contractBasis(row: Pick<FuturesContract, "price" | "stale" | "expiration" | "asOf">, bars: readonly SpotBar[] | null): ContractBasis {
|
|
489
|
+
if (!bars || row.stale || !positive(row.price)) return NO_BASIS;
|
|
490
|
+
const printed = parseReportTime(row.asOf);
|
|
491
|
+
if (!printed || printed.dateOnly) return { ...NO_BASIS, unpaired: { print: null, spot: null } };
|
|
492
|
+
const minute = minuteOf(printed.time);
|
|
493
|
+
const bar = nearestSpotBar(bars, minute);
|
|
494
|
+
if (!bar || bar.minute !== minute) return { ...NO_BASIS, unpaired: { print: printed.time, spot: bar?.minute ?? null } };
|
|
495
|
+
const days = daysToExpiry(printed.time, row.expiration);
|
|
496
|
+
return { vsSpotPct: vsSpotPct(row.price, bar.price), annualisedBasisPct: annualisedBasisPct(row.price, bar.price, days),
|
|
497
|
+
spot: bar.price, spotTime: isoMinute(minute), daysToExpiry: days, unpaired: null };
|
|
390
498
|
}
|
|
391
499
|
|
|
392
500
|
/** A basis in percent, signed; one that rounds to zero stays unsigned. */
|
|
@@ -408,23 +516,18 @@ export function curveSpotLabel(spot: CurveSpot, root: string, now: number): stri
|
|
|
408
516
|
/** The basis columns' sort values, which live beside the contract rather than on it. */
|
|
409
517
|
export type CurveBasisRows = ReadonlyMap<string, ContractBasis>;
|
|
410
518
|
|
|
411
|
-
export function curveBasisRows(rows: readonly FuturesContract[],
|
|
412
|
-
return new Map(rows.map((row) => [row.symbol,
|
|
519
|
+
export function curveBasisRows(rows: readonly FuturesContract[], bars: readonly SpotBar[] | null): CurveBasisRows {
|
|
520
|
+
return new Map(rows.map((row) => [row.symbol, contractBasis(row, bars)]));
|
|
413
521
|
}
|
|
414
522
|
|
|
415
|
-
/** The contracts a
|
|
416
|
-
export function
|
|
523
|
+
/** The contracts a known set of spot bars left blank for timing: no time of day, or no bar in their minute. */
|
|
524
|
+
export function unpairedContractCount(basis: Iterable<ContractBasis>): number {
|
|
417
525
|
let count = 0;
|
|
418
|
-
for (const row of basis) if (row.
|
|
526
|
+
for (const row of basis) if (row.unpaired) count += 1;
|
|
419
527
|
return count;
|
|
420
528
|
}
|
|
421
529
|
|
|
422
|
-
/**
|
|
423
|
-
export function thinContractsNotice(count: number): string {
|
|
424
|
-
return `Basis blank on ${count} thin contract${count === 1 ? "" : "s"} (last print over 1h before spot)`;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/** What the quote path reports of the spot itself, as the footer names it: `CCC, real-time`. Null when it reports neither. */
|
|
530
|
+
/** What the quote path reports of the spot itself, as the footer names it: `crypto composite price, real-time`. Null when it reports neither. */
|
|
428
531
|
export function curveSpotSource(spot: Pick<CurveSpot, "venue" | "feed">): string | null {
|
|
429
532
|
const parts = [spot.venue, spot.feed].filter((part): part is string => !!part);
|
|
430
533
|
return parts.length ? parts.join(", ") : null;
|
|
@@ -433,19 +536,39 @@ export function curveSpotSource(spot: Pick<CurveSpot, "venue" | "feed">): string
|
|
|
433
536
|
/** What Ann Basis is: Vs Spot is the same ratio before it is annualised. */
|
|
434
537
|
export const BASIS_FORMULA = "(Last / spot - 1) × 365 / days to expiry";
|
|
435
538
|
/** The two basis columns' convention in one line. */
|
|
436
|
-
export const BASIS_CONVENTION = `Ann Basis = ${BASIS_FORMULA}: simple actual/365,
|
|
539
|
+
export const BASIS_CONVENTION = `Ann Basis = ${BASIS_FORMULA}: simple actual/365, each last trade against spot in the same minute, `
|
|
540
|
+
+ "with days counted to final settlement at 16:00 London on the last trading day.";
|
|
437
541
|
|
|
438
|
-
/**
|
|
542
|
+
/** A gap in whole minutes as a reader counts it: `5 min`, `3 h`, `2 days`. */
|
|
543
|
+
function gapText(minutes: number): string {
|
|
544
|
+
if (minutes < 120) return `${minutes} min`;
|
|
545
|
+
const hours = Math.floor(minutes / 60);
|
|
546
|
+
return hours < 48 ? `${hours} h` : `${Math.floor(hours / 24)} days`;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/** The UTC minutes a blank names, the date only when the two fall on different days. */
|
|
550
|
+
function pairTimes(print: number, spot: number): string {
|
|
551
|
+
const [printDate, printTime] = curveTimestamp(new Date(print).toISOString()).split(" ");
|
|
552
|
+
const [spotDate, spotTime] = curveTimestamp(new Date(spot).toISOString()).split(" ");
|
|
553
|
+
return printDate === spotDate ? `print ${printTime}, nearest spot ${spotTime} UTC` : `print ${printDate} ${printTime}, nearest spot ${spotDate} ${spotTime} UTC`;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/** Why one priced-or-not contract has no basis against known spot bars, in the order `contractBasis` decides it. */
|
|
439
557
|
function blankReason(row: Pick<FuturesContract, "price" | "stale">, basis: ContractBasis): string | null {
|
|
440
558
|
if (basis.vsSpotPct != null) return null;
|
|
441
559
|
if (!positive(row.price)) return "no price";
|
|
442
560
|
if (row.stale) return "price over two sessions old";
|
|
443
|
-
|
|
561
|
+
const unpaired = basis.unpaired;
|
|
562
|
+
if (!unpaired) return null;
|
|
563
|
+
if (unpaired.print == null) return "last trade has no time of day";
|
|
564
|
+
if (unpaired.spot == null) return "no one-minute spot prices";
|
|
565
|
+
const minutes = Math.round(Math.abs(minuteOf(unpaired.print) - unpaired.spot) / MINUTE_MS);
|
|
566
|
+
return `spot and print ${gapText(minutes)} apart: ${pairTimes(unpaired.print, unpaired.spot)}`;
|
|
444
567
|
}
|
|
445
568
|
|
|
446
569
|
/**
|
|
447
|
-
* The contracts whose basis cells are blank against
|
|
448
|
-
* unexplained: the far months of a curve print rarely, and a
|
|
570
|
+
* The contracts whose basis cells are blank against known spot bars, grouped by cause and named, so a blank is
|
|
571
|
+
* never unexplained: the far months of a curve print rarely, and a trade no spot bar shares a minute with is not read.
|
|
449
572
|
*/
|
|
450
573
|
export function blankBasisNote(rows: readonly Pick<FuturesContract, "symbol" | "price" | "stale">[], basis: CurveBasisRows): string | null {
|
|
451
574
|
const groups = new Map<string, string[]>();
|
|
@@ -457,29 +580,37 @@ export function blankBasisNote(rows: readonly Pick<FuturesContract, "symbol" | "
|
|
|
457
580
|
return groups.size ? `Basis blank for ${[...groups].map(([reason, codes]) => `${codes.join(", ")} (${reason})`).join("; ")}.` : null;
|
|
458
581
|
}
|
|
459
582
|
|
|
460
|
-
/** Under this many days to expiry a few basis points of spot move the annualised rate by whole points. */
|
|
461
|
-
const SHORT_DATED_DAYS =
|
|
462
|
-
/** The noise the note sizes the swing against: ten basis points of spot, a
|
|
583
|
+
/** Under this many days to expiry a few basis points of spot move the annualised rate by whole points: Vs Spot leads and the rate is greyed. */
|
|
584
|
+
const SHORT_DATED_DAYS = 7;
|
|
585
|
+
/** The noise the note sizes the swing against: ten basis points of spot, a CME trade's usual gap to a composite price in the same minute. */
|
|
463
586
|
const SPOT_NOISE_PCT = 0.1;
|
|
464
587
|
|
|
588
|
+
/** A contract whose annualised basis is shown inside `SHORT_DATED_DAYS` of final settlement, where spot noise swamps it. */
|
|
589
|
+
export function shortDatedBasis(basis: ContractBasis | null | undefined): boolean {
|
|
590
|
+
return basis?.annualisedBasisPct != null && basis.daysToExpiry != null && basis.daysToExpiry < SHORT_DATED_DAYS;
|
|
591
|
+
}
|
|
592
|
+
|
|
465
593
|
/** The note for contracts showing an annualised basis inside `SHORT_DATED_DAYS`: what 10 bp of spot noise does to each. */
|
|
466
|
-
export function shortDatedBasisNote(rows: readonly Pick<FuturesContract, "symbol"
|
|
467
|
-
if (!spot || spot.status !== "ok" || spot.asOf == null) return null;
|
|
468
|
-
const spotTime = Date.parse(spot.asOf);
|
|
594
|
+
export function shortDatedBasisNote(rows: readonly Pick<FuturesContract, "symbol">[], basis: CurveBasisRows): string | null {
|
|
469
595
|
const near = rows.flatMap((row) => {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
596
|
+
const cell = basis.get(row.symbol);
|
|
597
|
+
if (!shortDatedBasis(cell)) return [];
|
|
598
|
+
const days = cell!.daysToExpiry!;
|
|
599
|
+
return [`${curveContractCode(row.symbol)} (${days.toFixed(1)} days) by ±${(SPOT_NOISE_PCT * 365 / days).toFixed(1)} points`];
|
|
473
600
|
});
|
|
474
|
-
return near.length ? `Ann Basis is noisy under ${SHORT_DATED_DAYS} days to expiry: 10 bp of spot noise moves ${near.join(", ")}.` : null;
|
|
601
|
+
return near.length ? `Ann Basis is noisy under ${SHORT_DATED_DAYS} days to expiry, so read Vs Spot there: 10 bp of spot noise moves ${near.join(", ")}.` : null;
|
|
475
602
|
}
|
|
476
603
|
|
|
477
|
-
/**
|
|
478
|
-
|
|
604
|
+
/**
|
|
605
|
+
* A past date for the as-of view: empty (or "latest") for the live curve, else
|
|
606
|
+
* YYYY-MM-DD no later than today. `option` is how a command line types it
|
|
607
|
+
* (`--date`), empty for the pane's field.
|
|
608
|
+
*/
|
|
609
|
+
export function curveAsOfDate(value: unknown, now = new Date(), option = ""): string {
|
|
479
610
|
const text = typeof value === "string" ? value.trim() : "";
|
|
480
611
|
if (!text || text.toLowerCase() === "latest") return "";
|
|
481
612
|
const date = readCalendarDate(text);
|
|
482
|
-
if (!date) throw new Error(
|
|
613
|
+
if (!date) throw new Error(dateOptionError(text, option, { now, subject: "an as-of date", formats: dateOptionFormatsOr("latest") }));
|
|
483
614
|
if (date > now.toISOString().slice(0, 10)) throw new Error("A futures curve cannot use a future date.");
|
|
484
615
|
return date;
|
|
485
616
|
}
|
|
@@ -531,6 +662,61 @@ export function withTradedExpirations(data: FuturesCurvePayload): FuturesCurvePa
|
|
|
531
662
|
};
|
|
532
663
|
}
|
|
533
664
|
|
|
665
|
+
/**
|
|
666
|
+
* The trading date a print belongs to, as the server dates sessions: CME's
|
|
667
|
+
* session for a date opens at 18:00 New York the evening before (22:00 or
|
|
668
|
+
* 23:00 UTC), so a two-hour shift puts those evening trades on the next date
|
|
669
|
+
* and leaves day-only venues as they are. A settlement's date is its session.
|
|
670
|
+
*/
|
|
671
|
+
function curveSessionDate(asOf: string): string {
|
|
672
|
+
return asOf.length === 10 ? asOf : new Date(Date.parse(asOf) + 2 * 3_600_000).toISOString().slice(0, 10);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* The settlement session a live contract has not traded since: its Settle
|
|
677
|
+
* column shows that session's settlement and its latest price is from that
|
|
678
|
+
* session or before. Null when it has traded since, or shows no settlement. A
|
|
679
|
+
* Cboe price is the settlement itself, so it has no trade to wait for.
|
|
680
|
+
*/
|
|
681
|
+
export function curveNoTradeSince(row: Pick<FuturesContract, "price" | "settlement" | "asOf">,
|
|
682
|
+
data: Pick<FuturesCurvePayload, "source" | "settlementDate">): string | null {
|
|
683
|
+
const session = data.settlementDate;
|
|
684
|
+
if (data.source === "cboe" || !session || row.price == null || row.settlement == null || !row.asOf) return null;
|
|
685
|
+
return curveSessionDate(row.asOf) <= session ? session : null;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* The live curve with every Change on the basis its table states: the last
|
|
690
|
+
* trade less the settlement in the Settle column. The source's session change
|
|
691
|
+
* is from the settlement before the contract's own last trade, so a back month
|
|
692
|
+
* that last traded on the settlement's session read against the session
|
|
693
|
+
* before it, beside front months read against the one shown. A contract with
|
|
694
|
+
* no trade since the settlement (curveNoTradeSince), or no settlement shown,
|
|
695
|
+
* has no change. A Cboe price is a settlement, and its change, from the
|
|
696
|
+
* settlement before, is kept.
|
|
697
|
+
*/
|
|
698
|
+
export function withSettleChanges(data: FuturesCurvePayload): FuturesCurvePayload {
|
|
699
|
+
if (data.source === "cboe") return data;
|
|
700
|
+
return { ...data, contracts: data.contracts.map((row) => {
|
|
701
|
+
const change = row.price != null && row.settlement != null && data.settlementDate && row.asOf && !curveNoTradeSince(row, data)
|
|
702
|
+
? row.price - row.settlement : null;
|
|
703
|
+
return change === (row.change ?? null) ? row : { ...row, change };
|
|
704
|
+
}) };
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* The contracts whose Change is blank because they have not traded since the
|
|
709
|
+
* settlement shown, named, in the words the basis notes use; a pane with no
|
|
710
|
+
* room for the names counts them.
|
|
711
|
+
*/
|
|
712
|
+
export function noTradeChangeNote(rows: readonly Pick<FuturesContract, "symbol" | "price" | "settlement" | "asOf">[],
|
|
713
|
+
data: Pick<FuturesCurvePayload, "source" | "settlementDate">, options: { count?: boolean } = {}): string | null {
|
|
714
|
+
const untraded = rows.filter((row) => curveNoTradeSince(row, data) != null).map((row) => curveContractCode(row.symbol));
|
|
715
|
+
if (!untraded.length) return null;
|
|
716
|
+
const named = options.count ? `on ${untraded.length} contract${untraded.length === 1 ? "" : "s"}` : `for ${untraded.join(", ")}`;
|
|
717
|
+
return `Change blank ${named} (no trade since ${data.settlementDate})${options.count ? "" : "."}`;
|
|
718
|
+
}
|
|
719
|
+
|
|
534
720
|
/**
|
|
535
721
|
* The archived curve on a past date in the live curve's shape, so the pane
|
|
536
722
|
* draws it the same way. Its week- and month-back ghosts are the curves as
|
|
@@ -566,6 +752,8 @@ export function archivedFuturesCurve(root: string, curve: FuturesCurveAsOfPayloa
|
|
|
566
752
|
const settled = contracts.filter((row) => row.settlement != null);
|
|
567
753
|
const [front, next] = settled.length >= 2 ? settled : settled.length ? [] : contracts.filter((row) => !row.stale);
|
|
568
754
|
const value = front && next ? next.price! - front.price! : null;
|
|
755
|
+
// A leg that traded under THIN_SPREAD_LOTS lots that session gets no slope call, as on the live curve.
|
|
756
|
+
const thin = [front, next].find((row) => row?.volume != null && row.volume < THIN_SPREAD_LOTS)?.symbol ?? null;
|
|
569
757
|
const days = front && next ? (Date.parse(next.expiration) - Date.parse(front.expiration)) / DAY_MS : 0;
|
|
570
758
|
const roll = front && next && front.price! > 0 && next.price! > 0 && days > 0 ? (front.price! / next.price! - 1) * 365 / days * 100 : null;
|
|
571
759
|
return {
|
|
@@ -574,7 +762,8 @@ export function archivedFuturesCurve(root: string, curve: FuturesCurveAsOfPayloa
|
|
|
574
762
|
catalogue: { method: "provider", complete: true, horizonEnd: null }, contracts, ghosts,
|
|
575
763
|
slope: { frontSymbol: front?.symbol ?? null, nextSymbol: next?.symbol ?? null, value, annualizedRollYield: roll, percentile: null,
|
|
576
764
|
rollPercentile: null, samples: 0, historyStart: null, historyEnd: null, asOf: front && next ? curve.asOf : null,
|
|
577
|
-
|
|
765
|
+
basis: front && next ? settled.length >= 2 ? "settle" : "last" : null, thinSymbol: value == null ? null : thin,
|
|
766
|
+
state: value == null ? "unavailable" : thin ? "thin" : Math.abs(value) < 1e-10 ? "flat" : value > 0 ? "contango" : "backwardation" },
|
|
578
767
|
gaps: curve.gaps, spec: curve.spec ?? null, settlementDate: settled.length ? curve.asOf : null,
|
|
579
768
|
};
|
|
580
769
|
}
|