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
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import type { HeadlessPaneDefinition } from "../../../types/plugin";
|
|
2
2
|
import { parsePublicTickerKey } from "../../../utils/exchanges";
|
|
3
|
+
import { DATE_OPTION_EXAMPLES } from "../../../utils/calendar-date";
|
|
3
4
|
import {
|
|
4
5
|
expirationOptionSeconds, OPTION_EXPIRATION_FORMAT, OPTION_EXPIRATION_PLACEHOLDER, readOptionExpiration,
|
|
5
6
|
} from "../../../utils/option-expiry";
|
|
6
7
|
import { resolveHeadlessInstrument } from "../shared/headless-market-data";
|
|
7
8
|
import {
|
|
8
9
|
createScenarioDependencies, loadScenarioMarket, SCENARIO_STRATEGIES, scenarioControlsFromSettings, scenarioPositionFromSettings,
|
|
9
|
-
scenarioSpotBasis, suppliedScenarioInputs, type ScenarioMarketSnapshot,
|
|
10
|
+
scenarioSpotBasis, scenarioSpotStamp, suppliedScenarioInputs, type ScenarioMarketSnapshot,
|
|
10
11
|
} from "./client";
|
|
11
12
|
import { scenarioFreshness } from "./freshness";
|
|
12
13
|
import { cashSecuredPut, cspReportEntries, loadNextEarningsDate } from "./csp";
|
|
13
14
|
import { formatSpotTime } from "../options/model-spot";
|
|
14
|
-
import { buildScenario, currencyLabel, parseLegs, scenarioValueUnit } from "./model";
|
|
15
|
-
import { hedgeInputsFromSettings, hedgeReportEntries, scenarioHedgeBudget } from "./hedge";
|
|
15
|
+
import { amountUnit, buildScenario, currencyLabel, exportPercent, parseLegs, scenarioValueUnit } from "./model";
|
|
16
|
+
import { hedgeInputsFromSettings, hedgeReportEntries, scenarioHedgeBudget, seededLegQuotes } from "./hedge";
|
|
16
17
|
import { collarReportEntries, scenarioCollar } from "./collar";
|
|
17
18
|
import { modelDividendYieldNote } from "../../../market-data/model-dividend-yield";
|
|
19
|
+
import { listingFateEmpty, loadListingFate } from "../../../tickers/listing-fate";
|
|
18
20
|
|
|
19
21
|
// Float noise at a flat origin or a breakeven prints as 0.00, not -0.00.
|
|
20
22
|
const money = (value: unknown) => typeof value === "number" ? (Math.abs(value) < 0.005 ? 0 : value).toFixed(2) : "--";
|
|
@@ -31,6 +33,12 @@ const VALUATION_LABELS: Record<string, (currency: string) => string> = {
|
|
|
31
33
|
thetaPerDay: (currency) => `Theta (${currency} per day)`, vegaPerPoint: (currency) => `Vega (${currency} per vol point)`,
|
|
32
34
|
rhoPerPoint: (currency) => `Rho (${currency} per rate point)`,
|
|
33
35
|
};
|
|
36
|
+
/** The unit an export names beside each Valuation figure: `per` is the currency for the position (`USD per contract`). */
|
|
37
|
+
const VALUATION_UNITS: Record<string, (currency: string, per: string) => string> = {
|
|
38
|
+
price: (_currency, per) => per, pnl: (_currency, per) => per, delta: () => "shares", gamma: () => "shares per 1.00 move",
|
|
39
|
+
thetaPerDay: (currency) => `${currency} per day`, vegaPerPoint: (currency) => `${currency} per vol point`,
|
|
40
|
+
rhoPerPoint: (currency) => `${currency} per rate point`,
|
|
41
|
+
};
|
|
34
42
|
|
|
35
43
|
export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
36
44
|
shape: "bundle", argument: { kind: "ticker", description: "Underlying ticker" },
|
|
@@ -39,7 +47,8 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
39
47
|
description: "A typed or chain-seeded options position valued across spot, date and volatility: its legs, value and Greeks, expiry risk and a "
|
|
40
48
|
+ "scenario P&L grid. With --nav and --budget-bps, how many contracts a hedge budget buys, the premium spent, the notional protected and "
|
|
41
49
|
+ "coverage of an equity sleeve. --strategy csp sells a cash-secured put: cash secured, premium, yield on cash, annualised yield, "
|
|
42
|
-
+ "distance out of the money, break-even, days to expiry and whether earnings fall
|
|
50
|
+
+ "the bid, ask and spread with the yield at the bid, distance out of the money, break-even, days to expiry and whether earnings fall "
|
|
51
|
+
+ "before expiry; CSP ranks the same put across several names. --strategy collar buys a put and sells "
|
|
43
52
|
+ "a call against the shares they cover: net premium, floor, cap and breakevens of the hedged position.",
|
|
44
53
|
discovery: { screenshotReadiness: "ready", limitations: ["European scenario values do not model early assignment or exercise."] },
|
|
45
54
|
options: [
|
|
@@ -52,6 +61,8 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
52
61
|
+ "csp, one short put sold at its midpoint with the cash to buy the shares set aside (a cash-secured put), "
|
|
53
62
|
+ "or collar, one long put and one short call on the same expiry with the shares they cover" },
|
|
54
63
|
{ key: "strike", type: "string", description: "The --strategy strike: the put, the vertical's long call or the straddle. Nearest the money when omitted" },
|
|
64
|
+
{ key: "delta", type: "string", placeholder: "0.30", example: "--strategy csp --delta 0.30 --expiration 2026-11-20",
|
|
65
|
+
description: "The --strategy csp or put put by its delta instead of --strike: the one whose delta is nearest this, as a put's delta reads without its sign" },
|
|
55
66
|
{ key: "putStrike", aliases: ["put-strike"], type: "string",
|
|
56
67
|
description: "The --strategy collar put bought. The quoted strike nearest 10% below spot when omitted" },
|
|
57
68
|
{ key: "callStrike", aliases: ["call-strike"], type: "string",
|
|
@@ -66,8 +77,8 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
66
77
|
{ key: "rate", type: "string", description: "Continuously compounded annual risk-free rate, percent" },
|
|
67
78
|
{ key: "dividendYield", aliases: ["dividend-yield"], type: "string", description: "Continuous annual dividend yield, percent" },
|
|
68
79
|
{ key: "currency", type: "string", description: "Currency of the inputs, such as USD; the underlying's when omitted" },
|
|
69
|
-
{ key: "asOf", aliases: ["as-of"], type: "string", description:
|
|
70
|
-
{ key: "date", type: "string", description:
|
|
80
|
+
{ key: "asOf", aliases: ["as-of"], type: "string", description: `Position valuation date, as ${DATE_OPTION_EXAMPLES}, or a UTC ISO timestamp` },
|
|
81
|
+
{ key: "date", type: "string", description: `Scenario date, as ${DATE_OPTION_EXAMPLES}, or a UTC ISO timestamp` },
|
|
71
82
|
{ key: "volShift", aliases: ["vol-shift"], type: "string", defaultValue: "0", description: "Parallel volatility shift, percentage points" },
|
|
72
83
|
{ key: "spotRange", aliases: ["spot-range"], type: "string", defaultValue: "30", description: "Spot grid range above and below current spot, percent" },
|
|
73
84
|
{ key: "nav", type: "string", description: "Portfolio NAV for a hedge budget, such as 100m, 2.5bn, 250k, 1,000,000 or $100m. Needs --budget-bps" },
|
|
@@ -77,17 +88,23 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
77
88
|
],
|
|
78
89
|
async load(args, ctx) {
|
|
79
90
|
const symbol = args.symbols[0]!;
|
|
91
|
+
// Several names to sell puts on are a screen, not one scenario.
|
|
92
|
+
const names = args.rawArgument.split(/[\s,;]+/).filter(Boolean);
|
|
93
|
+
if (names.length > 1 && args.options.strategy === "csp") {
|
|
94
|
+
throw new Error(`OSA values one underlying. To rank cash-secured puts across ${names.join(", ")}: gloom fn CSP ${names.join(" ")}`);
|
|
95
|
+
}
|
|
80
96
|
const settings: Record<string, unknown> = { ...ctx.settings, ...args.options, symbol };
|
|
81
97
|
// Bad hedge inputs fail before any market request.
|
|
82
98
|
hedgeInputsFromSettings(settings);
|
|
83
99
|
const suppliedInputs = suppliedScenarioInputs(settings);
|
|
84
100
|
let market: ScenarioMarketSnapshot;
|
|
101
|
+
let instrument: Awaited<ReturnType<typeof resolveHeadlessInstrument>> | null = null;
|
|
85
102
|
if (suppliedInputs) {
|
|
86
103
|
// An explicit position can be valued offline and must never depend on unrelated market requests.
|
|
87
104
|
market = { ...parsePublicTickerKey(symbol), spot: null, currency: "", asOf: Date.now(), chain: null, expirationDates: [], rate: null,
|
|
88
105
|
dividendYield: null, source: null, underlyingQuote: null, rateAsOf: [], warnings: [] };
|
|
89
106
|
} else {
|
|
90
|
-
|
|
107
|
+
instrument = await resolveHeadlessInstrument(ctx, symbol);
|
|
91
108
|
const typedExpiries = typeof settings.legs === "string" && settings.legs.trim() ? parseLegs(settings.legs).map((leg) => leg.expiration) : [];
|
|
92
109
|
const expiration = readOptionExpiration(args.options.expiration);
|
|
93
110
|
market = await loadScenarioMarket({ instrument, expiration: expiration ?? undefined,
|
|
@@ -104,14 +121,20 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
104
121
|
// A typed rate or yield stands in for the source that could not supply one.
|
|
105
122
|
const marketWarnings = market.warnings.filter((warning) => !(supplied(settings.dividendYield) && warning.startsWith("Dividend yield unavailable"))
|
|
106
123
|
&& !(supplied(settings.rate) && warning.startsWith("Treasury")));
|
|
107
|
-
const
|
|
124
|
+
const loadErrors = scenario ? [...new Set([...marketWarnings, ...scenario.warnings])]
|
|
108
125
|
: [...marketWarnings, "No position supplied; add --legs or select --strategy"];
|
|
126
|
+
// A symbol with no option chain at all says what became of it when something did (TWTR stopped
|
|
127
|
+
// trading, FB is a fund now) in place of the chain's errors.
|
|
128
|
+
const fate = instrument && !market.chain && !scenario
|
|
129
|
+
? listingFateEmpty(await loadListingFate(instrument, ctx.marketData, market.underlyingQuote ? { quote: market.underlyingQuote } : {}), loadErrors) : null;
|
|
130
|
+
const errors = fate?.errors ?? loadErrors;
|
|
109
131
|
const midVolatility = !!position?.legs.some((leg) => leg.volatilitySource === "mid");
|
|
110
132
|
// A seeded strategy starts at the spot its quote mids imply; the last print is reported beside it.
|
|
111
133
|
const lastPrint = midVolatility && !supplied(settings.spot) && market.spot != null && money(market.spot) !== money(position!.spot)
|
|
112
134
|
? market.spot : null;
|
|
113
135
|
const spotBasis = position ? scenarioSpotBasis(settings, position, market) : null;
|
|
114
|
-
const csp = position && settings.strategy === "csp"
|
|
136
|
+
const csp = position && settings.strategy === "csp"
|
|
137
|
+
? cashSecuredPut(position, spotBasis!, earningsDate, seededLegQuotes(position, market.chain).get(position.legs[0]?.id ?? "")) : null;
|
|
115
138
|
// A collar seeded, or one typed with the shares it hedges.
|
|
116
139
|
const collar = position && (settings.strategy === "collar" || position.underlying) ? scenarioCollar(position, spotBasis!) : null;
|
|
117
140
|
const lastSession = market.underlyingQuote && spotBasis === "implied by option quotes"
|
|
@@ -122,6 +145,10 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
122
145
|
// Value, P&L, risk and the grid add every contract; entry prices and spot are per share.
|
|
123
146
|
const valueUnit = position ? scenarioValueUnit(position) : null;
|
|
124
147
|
const per = `${currency} ${valueUnit}`;
|
|
148
|
+
// What an export names beside each number: the currency (or `currency unknown`) and what it is for.
|
|
149
|
+
const exportCurrency = position ? amountUnit(position.currency) : "";
|
|
150
|
+
const exportPer = `${exportCurrency} ${valueUnit}`;
|
|
151
|
+
const perShare = `${exportCurrency} ${PRICE_UNIT}`;
|
|
125
152
|
return {
|
|
126
153
|
freshness: scenarioFreshness(market, suppliedInputs),
|
|
127
154
|
sections: scenario ? [
|
|
@@ -134,16 +161,16 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
134
161
|
], rows: position!.legs.map((leg) => ({ ...leg, expiry: new Date(leg.expiration * 1000).toISOString().slice(0, 10),
|
|
135
162
|
...(midVolatility ? { volatilityFrom: leg.volatilitySource === "mid" ? "quote mid" : "provider" } : {}) })) },
|
|
136
163
|
{ title: "Inputs", entries: [
|
|
137
|
-
{ key: "spot", label: lastPrint != null ? "Spot implied by option quotes" : "Spot", value: position!.spot,
|
|
138
|
-
formatted: `${money(position!.spot)} ${PRICE_UNIT}${lastPrint == null && spotBasis !== "last price" ? ` (${spotBasis})` : ""}` },
|
|
139
|
-
...(lastPrint != null ? [{ key: "last", label: "Last price", value: lastPrint,
|
|
140
|
-
formatted: `${money(lastPrint)} ${PRICE_UNIT}${lastSession && lastSession !== "last price" ? ` (${lastSession})` : ""}` }] : []),
|
|
141
|
-
...(position!.underlying ? [{ key: "shares", label: "Shares held", value: position!.underlying.quantity,
|
|
164
|
+
{ key: "spot", label: lastPrint != null ? "Spot implied by option quotes" : "Spot", value: position!.spot, unit: perShare,
|
|
165
|
+
formatted: `${money(position!.spot)} ${PRICE_UNIT}${lastPrint == null && spotBasis !== "last price" ? ` (${scenarioSpotStamp(spotBasis!, position!.asOf)})` : ""}` },
|
|
166
|
+
...(lastPrint != null ? [{ key: "last", label: "Last price", value: lastPrint, unit: perShare,
|
|
167
|
+
formatted: `${money(lastPrint)} ${PRICE_UNIT}${lastSession && lastSession !== "last price" ? ` (${scenarioSpotStamp(lastSession, market.asOf)})` : ""}` }] : []),
|
|
168
|
+
...(position!.underlying ? [{ key: "shares", label: "Shares held", value: position!.underlying.quantity, unit: "shares",
|
|
142
169
|
formatted: `${position!.underlying.quantity.toLocaleString("en-US")} at ${money(position!.underlying.price)} ${PRICE_UNIT}` }] : []),
|
|
143
170
|
{ key: "asOf", label: "Valued at", value: new Date(position!.asOf).toISOString(), formatted: formatSpotTime(position!.asOf) },
|
|
144
|
-
{ key: "rate", label: "Rate", value: position!.rate, formatted: percent(position!.rate) },
|
|
171
|
+
{ key: "rate", label: "Rate", value: exportPercent(position!.rate), unit: "%", formatted: percent(position!.rate) },
|
|
145
172
|
// A yield read as 0 because no dividend was paid, or the dividend stopped, says so; a stated or typed one is the figure alone.
|
|
146
|
-
{ key: "dividendYield", label: "Dividend yield", value: position!.dividendYield, formatted: percent(position!.dividendYield)
|
|
173
|
+
{ key: "dividendYield", label: "Dividend yield", value: exportPercent(position!.dividendYield), unit: "%", formatted: percent(position!.dividendYield)
|
|
147
174
|
+ (dividendNote ? ` (${dividendNote})` : "") },
|
|
148
175
|
{ key: "currency", label: "Currency", value: position!.currency, formatted: currency! },
|
|
149
176
|
] },
|
|
@@ -151,12 +178,13 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
151
178
|
...(csp ? [{ title: "Cash-secured put", entries: cspReportEntries(csp) }] : []),
|
|
152
179
|
...(collar ? [{ title: "Collar", entries: collarReportEntries(collar) }] : []),
|
|
153
180
|
{ title: `Valuation (${per})`, entries: Object.entries(scenario.valuation).map(([key, value]) => ({ key,
|
|
154
|
-
label: VALUATION_LABELS[key]?.(currency!) ?? key, value, formatted: money(value)
|
|
181
|
+
label: VALUATION_LABELS[key]?.(currency!) ?? key, value, formatted: money(value),
|
|
182
|
+
...(VALUATION_UNITS[key] ? { unit: VALUATION_UNITS[key]!(exportCurrency, exportPer) } : {}) })) },
|
|
155
183
|
{ title: `Expiry risk (${per})`, entries: [
|
|
156
|
-
{ key: "breakevens", label: "Breakevens (spot)", value: scenario.expiryRisk.breakevens,
|
|
184
|
+
{ key: "breakevens", label: "Breakevens (spot)", value: scenario.expiryRisk.breakevens, unit: perShare,
|
|
157
185
|
formatted: scenario.expiryRisk.breakevens.map(money).join(", ") || "none" },
|
|
158
|
-
{ key: "maxProfit", label: "Max profit", value: scenario.expiryRisk.maxProfit, formatted: scenario.expiryRisk.unlimitedProfit ? "Unlimited" : money(scenario.expiryRisk.maxProfit) },
|
|
159
|
-
{ key: "maxLoss", label: "Max loss", value: scenario.expiryRisk.maxLoss, formatted: scenario.expiryRisk.unlimitedLoss ? "Unlimited" : money(scenario.expiryRisk.maxLoss) },
|
|
186
|
+
{ key: "maxProfit", label: "Max profit", value: scenario.expiryRisk.maxProfit, unit: exportPer, formatted: scenario.expiryRisk.unlimitedProfit ? "Unlimited" : money(scenario.expiryRisk.maxProfit) },
|
|
187
|
+
{ key: "maxLoss", label: "Max loss", value: scenario.expiryRisk.maxLoss, unit: exportPer, formatted: scenario.expiryRisk.unlimitedLoss ? "Unlimited" : money(scenario.expiryRisk.maxLoss) },
|
|
160
188
|
...(scenario.expiryRisk.reason ? [{ key: "limitation", label: "Limitation", value: scenario.expiryRisk.reason }] : []),
|
|
161
189
|
] },
|
|
162
190
|
{ title: `Scenario grid (P&L, ${per})`, columns: [
|
|
@@ -167,7 +195,7 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
|
167
195
|
...Object.fromEntries(row.values.map((value, index) => [`date${index}`, value])) })) },
|
|
168
196
|
] : [],
|
|
169
197
|
complete: scenario != null && errors.length === 0,
|
|
170
|
-
unavailableSymbols: scenario ? [] : [symbol], errors,
|
|
198
|
+
unavailableSymbols: scenario ? [] : [symbol], errors, ...(fate?.empty ? { empty: fate.empty } : {}),
|
|
171
199
|
metadata: { scenario, position, controls, market, ...(hedge ? { hedge } : {}), ...(csp ? { csp } : {}), ...(collar ? { collar } : {}),
|
|
172
200
|
...(position ? { spot: { price: position.spot, basis: spotBasis, valuedAt: new Date(position.asOf).toISOString() } } : {}),
|
|
173
201
|
inputSource: suppliedInputs ? "user" : "market",
|
|
@@ -3,7 +3,7 @@ import type { OptionsChain } from "../../../types/financials";
|
|
|
3
3
|
import type { HeadlessPaneEntry } from "../../../types/headless";
|
|
4
4
|
import { numberErrorMessage } from "../../../utils/decimal-comma";
|
|
5
5
|
import { formatCompact } from "../../../utils/format";
|
|
6
|
-
import { UNKNOWN_CURRENCY, type ScenarioPosition } from "./model";
|
|
6
|
+
import { amountUnit, exportPercent, UNKNOWN_CURRENCY, type ScenarioPosition } from "./model";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Hedge budget sizing (docs/research-data.md#options-scenario-analysis): how
|
|
@@ -118,9 +118,10 @@ export interface HedgeQuote { bid: number; ask: number }
|
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
120
|
* The bid and ask of each leg a strategy seeded from the chain, by leg id: the
|
|
121
|
-
* chain's, or the leg's streamed quote when the pane follows the market.
|
|
121
|
+
* chain's, or the leg's streamed quote when the pane follows the market. A
|
|
122
|
+
* typed leg has none.
|
|
122
123
|
*/
|
|
123
|
-
function
|
|
124
|
+
export function seededLegQuotes(
|
|
124
125
|
position: ScenarioPosition, chain: OptionsChain | null | undefined, liveQuotes?: ReadonlyMap<string, HedgeQuote>,
|
|
125
126
|
): Map<string, HedgeQuote> {
|
|
126
127
|
const contracts = new Map([...(chain?.calls ?? []), ...(chain?.puts ?? [])].map((contract) => [contract.contractSymbol, contract]));
|
|
@@ -206,7 +207,7 @@ export function scenarioHedgeBudget(
|
|
|
206
207
|
const inputs = hedgeInputsFromSettings(settings);
|
|
207
208
|
if (!inputs) return null;
|
|
208
209
|
if (!position?.legs.length) throw new Error("A hedge budget needs a position; add --legs or select --strategy.");
|
|
209
|
-
return sizeHedgeBudget(position, inputs, { quotes:
|
|
210
|
+
return sizeHedgeBudget(position, inputs, { quotes: seededLegQuotes(position, market?.chain, market?.liveQuotes),
|
|
210
211
|
spot: hedgeSpot(position, market?.spot, supplied(settings.spot)) });
|
|
211
212
|
}
|
|
212
213
|
|
|
@@ -246,21 +247,26 @@ function costText(cost: number, sizingPrice: number | null, multiplier: number,
|
|
|
246
247
|
/** The report's Hedge budget section; `value` keeps full precision, `formatted` is what text output prints. */
|
|
247
248
|
export function hedgeReportEntries(hedge: HedgeBudget): HeadlessPaneEntry[] {
|
|
248
249
|
const unit = hedge.currency && hedge.currency !== UNKNOWN_CURRENCY ? ` ${hedge.currency}` : "";
|
|
250
|
+
// Each figure's `value` is in its `unit`, a share of NAV in percent, so an export writes the number and its unit.
|
|
251
|
+
const amount = { unit: amountUnit(hedge.currency) };
|
|
249
252
|
return [
|
|
250
|
-
{ key: "nav", label: "NAV", value: hedge.nav, formatted: `${money(hedge.nav)}${unit}` },
|
|
251
|
-
{ key: "budget", label: "Budget", value: hedge.budget, formatted: `${money(hedge.budget)}${unit} (${formatBps(hedge.budgetBps)} of NAV)` },
|
|
252
|
-
{ key: "sizingPrice", label: "Sizing price", value: hedge.sizingPrice,
|
|
253
|
+
{ key: "nav", label: "NAV", value: hedge.nav, ...amount, formatted: `${money(hedge.nav)}${unit}` },
|
|
254
|
+
{ key: "budget", label: "Budget", value: hedge.budget, ...amount, formatted: `${money(hedge.budget)}${unit} (${formatBps(hedge.budgetBps)} of NAV)` },
|
|
255
|
+
{ key: "sizingPrice", label: "Sizing price", value: hedge.sizingPrice, unit: `${amount.unit} per share`,
|
|
253
256
|
formatted: hedge.sizingPrice == null ? "--" : describePrice(hedge.basis, hedge.singleLeg, hedge.sizingPrice) },
|
|
254
|
-
{ key: "costPerContract", label: "Cost per contract", value: hedge.costPerContract,
|
|
255
|
-
|
|
256
|
-
{ key: "
|
|
257
|
-
{ key: "
|
|
258
|
-
{ key: "
|
|
257
|
+
{ key: "costPerContract", label: "Cost per contract", value: hedge.costPerContract, ...amount,
|
|
258
|
+
formatted: costText(hedge.costPerContract, hedge.sizingPrice, hedge.multiplier, unit) },
|
|
259
|
+
{ key: "contracts", label: "Contracts", value: hedge.contracts, unit: "contracts", formatted: hedge.contracts.toLocaleString("en-US") },
|
|
260
|
+
{ key: "premium", label: "Premium spent", value: hedge.premium, ...amount, formatted: `${money(hedge.premium)}${unit}` },
|
|
261
|
+
{ key: "premiumBps", label: "Premium / NAV", value: hedge.premiumBps, unit: "bp",
|
|
262
|
+
formatted: `${formatBps(hedge.premiumBps)} (${(hedge.premiumBps / 100).toFixed(2)}% of NAV)` },
|
|
263
|
+
{ key: "notional", label: "Notional protected", value: hedge.notional, ...amount,
|
|
259
264
|
formatted: `${money(hedge.notional)}${unit} (${hedge.contracts.toLocaleString("en-US")} x ${hedge.multiplier} x ${formatHedgePrice(hedge.spot)})` },
|
|
260
|
-
{ key: "notionalOfNav", label: "Notional / NAV", value: hedge.notionalOfNav, formatted: percent(hedge.notionalOfNav) },
|
|
265
|
+
{ key: "notionalOfNav", label: "Notional / NAV", value: exportPercent(hedge.notionalOfNav), unit: "%", formatted: percent(hedge.notionalOfNav) },
|
|
261
266
|
hedge.coverage == null || hedge.sleeve == null
|
|
262
267
|
? { key: "coverage", label: "Coverage", value: null, formatted: "No equity sleeve given; add --sleeve <amount> to read notional against it" }
|
|
263
|
-
: { key: "coverage", label: "Coverage", value:
|
|
268
|
+
: { key: "coverage", label: "Coverage", value: exportPercent(hedge.coverage), unit: "%",
|
|
269
|
+
formatted: `${percent(hedge.coverage)} of a ${money(hedge.sleeve)}${unit} sleeve` },
|
|
264
270
|
];
|
|
265
271
|
}
|
|
266
272
|
|
|
@@ -2,8 +2,10 @@ import type { PluginModule } from "../plugin-module";
|
|
|
2
2
|
import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
|
|
3
3
|
import { OptionsScenarioPane } from "./pane";
|
|
4
4
|
import { optionsScenarioHeadless } from "./headless";
|
|
5
|
+
import { CspScreenPane } from "./csp-screen-pane";
|
|
6
|
+
import { cspScreenHeadless } from "./csp-screen-headless";
|
|
5
7
|
|
|
6
|
-
const scenarioSettingKeys = ["legs", "strategy", "strike", "putStrike", "callStrike", "shares", "expiration", "spot", "rate", "dividendYield", "currency", "asOf", "date", "volShift",
|
|
8
|
+
const scenarioSettingKeys = ["legs", "strategy", "strike", "delta", "putStrike", "callStrike", "shares", "expiration", "spot", "rate", "dividendYield", "currency", "asOf", "date", "volShift",
|
|
7
9
|
"spotRange", "seedLeg", "nav", "budgetBps", "sleeve"];
|
|
8
10
|
|
|
9
11
|
export const optionsScenarioModule: PluginModule = {
|
|
@@ -23,11 +25,34 @@ export const optionsScenarioModule: PluginModule = {
|
|
|
23
25
|
description: "The equity the hedge protects, for coverage: notional protected over the sleeve." },
|
|
24
26
|
],
|
|
25
27
|
},
|
|
28
|
+
}, {
|
|
29
|
+
id: "csp-screen", name: "Cash-Secured Put Screen", icon: "V", component: CspScreenPane,
|
|
30
|
+
defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 144, height: 24 },
|
|
31
|
+
tableExport: true, headless: cspScreenHeadless,
|
|
32
|
+
settings: {
|
|
33
|
+
title: "Cash-Secured Put Screen",
|
|
34
|
+
fields: [
|
|
35
|
+
{ key: "symbols", label: "Symbols", type: "text", placeholder: "JPM, GS, KO" },
|
|
36
|
+
{ key: "maxSpread", label: "Wide spread over (%)", type: "text", placeholder: "10",
|
|
37
|
+
description: "A put whose bid/ask spread is over this percent of its mid is marked wide. It is still ranked." },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
26
40
|
}],
|
|
27
|
-
paneTemplates: [
|
|
41
|
+
paneTemplates: [{
|
|
42
|
+
id: "csp-screen-pane", paneId: "csp-screen", label: "Cash-Secured Put Screen",
|
|
43
|
+
description: "Cash-secured puts across a list, ranked by annualised yield at the bid, with % OTM, delta, IV rank, spread and an earnings flag.",
|
|
44
|
+
// The put-selling phrases lead here first, then to OSA for one name.
|
|
45
|
+
keywords: ["csp", "cash secured put", "cash-secured puts", "put selling", "selling puts", "sell put", "sell puts", "short put", "wheel",
|
|
46
|
+
"put screen", "premium yield"],
|
|
47
|
+
shortcut: { prefix: "CSP", argKind: "ticker-list" as const }, headless: cspScreenHeadless,
|
|
48
|
+
createInstance: (_context, options) => ({
|
|
49
|
+
title: "CSP", placement: "floating" as const,
|
|
50
|
+
settings: options?.symbols?.length ? { symbols: options.symbols.join(",") } : {},
|
|
51
|
+
}),
|
|
52
|
+
}, createTickerSurfacePaneTemplate({
|
|
28
53
|
id: "options-scenario-pane", paneId: "options-scenario", label: "Options Scenario",
|
|
29
54
|
description: "Build multi-leg positions and compare scenario P&L, payoff and aggregate Greeks.",
|
|
30
|
-
// OSA
|
|
55
|
+
// OSA carries the put-selling phrases after CSP, which ranks names on them; OMON and VCA carry the same words, so a search finds all four.
|
|
31
56
|
keywords: ["osa", "options", "scenario", "payoff", "strategy", "greeks", "hedge", "hedging", "collar", "protective put", "put spread",
|
|
32
57
|
"cash secured put", "csp", "put selling", "sell put", "short put", "wheel"],
|
|
33
58
|
shortcut: "OSA", publicShare: true,
|
|
@@ -160,6 +160,19 @@ export function validateScenarioInputs(position: ScenarioPosition): string | nul
|
|
|
160
160
|
/** The stored stand-in for a currency nothing names; shown as `currency unknown`. */
|
|
161
161
|
export const UNKNOWN_CURRENCY = "UNKNOWN";
|
|
162
162
|
export const currencyLabel = (currency: string) => currency === UNKNOWN_CURRENCY ? "currency unknown" : currency;
|
|
163
|
+
/** The unit an export names beside an amount: the currency code, or `currency unknown`. */
|
|
164
|
+
export const amountUnit = (currency: string) => currency && currency !== UNKNOWN_CURRENCY ? currency : "currency unknown";
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* A fraction as the percent an export carries: a rate of 0.041 is 4.1, not
|
|
168
|
+
* the 4.1000000000000005 the product leaves. Twelve significant digits keep
|
|
169
|
+
* every digit a figure has; null stays null.
|
|
170
|
+
*/
|
|
171
|
+
export function exportPercent(fraction: number): number;
|
|
172
|
+
export function exportPercent(fraction: number | null | undefined): number | null;
|
|
173
|
+
export function exportPercent(fraction: number | null | undefined): number | null {
|
|
174
|
+
return fraction == null ? null : Number((fraction * 100).toPrecision(12));
|
|
175
|
+
}
|
|
163
176
|
|
|
164
177
|
/**
|
|
165
178
|
* The position's currency: the one typed, else the underlying's quote
|
|
@@ -26,7 +26,7 @@ import { buildOptionQuoteKey, freshOptionQuote, OPTIONS_QUOTE_EXCHANGE } from ".
|
|
|
26
26
|
import { liveScenarioPosition, scenarioLegContractSymbol } from "./live";
|
|
27
27
|
import { ScenarioPayoffChart } from "./charts";
|
|
28
28
|
import { ScenarioLegEditor, ScenarioSaveForm, ScenarioInputsForm } from "./editor";
|
|
29
|
-
import { loadScenarioMarket, scenarioControlsFromSettings, scenarioPositionFromSettings, scenarioSpotBasis, suppliedScenarioInputs,
|
|
29
|
+
import { loadScenarioMarket, scenarioControlsFromSettings, scenarioPositionFromSettings, scenarioSpotBasis, scenarioSpotStamp, scenarioSpotStampVariants, suppliedScenarioInputs,
|
|
30
30
|
type ScenarioMarketSnapshot } from "./client";
|
|
31
31
|
import { scenarioFreshness } from "./freshness";
|
|
32
32
|
import { cashSecuredPut, cspStatItems, loadNextEarningsDate } from "./csp";
|
|
@@ -38,8 +38,8 @@ import { buildScenario, currencyLabel, scenarioCurrency, scenarioValueUnit, UNKN
|
|
|
38
38
|
type ScenarioControls, validatePosition } from "./model";
|
|
39
39
|
import { EMPTY_SAVED_STRATEGIES, restoreSavedStrategies, type SavedScenarioStrategy } from "./state";
|
|
40
40
|
import { useScenarioEvidence } from "./evidence";
|
|
41
|
-
import { hedgeStatItems, scenarioHedgeBudget, type HedgeQuote } from "./hedge";
|
|
42
|
-
import { readOptionExpiration } from "../../../utils/option-expiry";
|
|
41
|
+
import { hedgeStatItems, scenarioHedgeBudget, seededLegQuotes, type HedgeQuote } from "./hedge";
|
|
42
|
+
import { isLiveOptionExpiry, readOptionExpiration } from "../../../utils/option-expiry";
|
|
43
43
|
import { parsePublicTickerKey } from "../../../utils/exchanges";
|
|
44
44
|
|
|
45
45
|
const EMPTY_ERRORS: string[] = [];
|
|
@@ -65,7 +65,9 @@ export function OptionsScenarioPane({ width, height, focused }: PaneProps) {
|
|
|
65
65
|
const underlying = listed.symbol;
|
|
66
66
|
const exchange = listed.exchange || target?.effectiveExchange || undefined;
|
|
67
67
|
// A strategy seeded for an expiry (`OSA SPY --strategy put --expiration 2027-01-15`) opens that expiry's chain.
|
|
68
|
-
const [
|
|
68
|
+
const [pickedExpiration, setExpiration] = usePluginPaneState<number | null>("chainExpiration", readOptionExpiration(settings.expiration));
|
|
69
|
+
// A picked expiry that has since lapsed gives way to the nearest live one, as OMON's does.
|
|
70
|
+
const expiration = pickedExpiration != null && isLiveOptionExpiry(pickedExpiration, Date.now(), exchange) ? pickedExpiration : null;
|
|
69
71
|
const [tab, setTab] = usePluginPaneState("activeTabId", "payoff");
|
|
70
72
|
const [detail, setDetail] = useState<"chain" | "leg" | "save" | "inputs" | null>(null);
|
|
71
73
|
const [editingLeg, setEditingLeg] = useState<ScenarioLeg | null>(null);
|
|
@@ -166,9 +168,11 @@ export function OptionsScenarioPane({ width, height, focused }: PaneProps) {
|
|
|
166
168
|
const earningsDate = frozenEarnings ? settings.scenarioEarningsDate as string | null : earnings.data;
|
|
167
169
|
// A position following the market is at the live print, which the footer names with its feed.
|
|
168
170
|
const spotBasis = scenario && !live ? scenarioSpotBasis(settings, scenario.position, market) : null;
|
|
171
|
+
// The put's bid and ask: its streamed quote while the pane follows the market, else the chain's.
|
|
169
172
|
const csp = useMemo(() => cspStrategy && scenario && !earnings.loading
|
|
170
|
-
? cashSecuredPut(scenario.position, live?.basis ?? spotBasis ?? "last price", earningsDate
|
|
171
|
-
|
|
173
|
+
? cashSecuredPut(scenario.position, live?.basis ?? spotBasis ?? "last price", earningsDate,
|
|
174
|
+
seededLegQuotes(scenario.position, market?.chain, live?.quotes).get(scenario.position.legs[0]?.id ?? "")) : null,
|
|
175
|
+
[cspStrategy, scenario, earnings.loading, earningsDate, live?.basis, live?.quotes, spotBasis, market?.chain]);
|
|
172
176
|
// A collar seeded, or one typed with the shares it hedges, as the report reads it.
|
|
173
177
|
const collarStrategy = settings.strategy === "collar";
|
|
174
178
|
const collar = useMemo(() => scenario && (collarStrategy || scenario.position.underlying)
|
|
@@ -294,11 +298,15 @@ export function OptionsScenarioPane({ width, height, focused }: PaneProps) {
|
|
|
294
298
|
const midLegs = live || !position ? 0 : position.legs.filter((leg) => leg.volatilitySource === "mid").length;
|
|
295
299
|
// A seed starts at the spot its quote mids imply, so name the last print when it differs.
|
|
296
300
|
const lastPrint = midLegs && (settings.spot == null || settings.spot === "") && market?.spot != null
|
|
297
|
-
&& money(market.spot) !== money(position!.spot)
|
|
301
|
+
&& money(market.spot) !== money(position!.spot)
|
|
302
|
+
? ` · ${(market.underlyingQuote ? extendedSession(market.underlyingQuote) : null) ?? "last"} ${money(market.spot)}` : "";
|
|
298
303
|
const midVolatility = !midLegs ? "" : (midLegs === position!.legs.length ? " · IV from quote mid"
|
|
299
304
|
: ` · IV from quote mid on ${midLegs} of ${position!.legs.length} legs`) + lastPrint;
|
|
300
305
|
// The spot every figure is valued at, and when: the live print, the spot the quote mids imply, a typed what-if or the last price.
|
|
301
|
-
|
|
306
|
+
// An extended-session print carries its own time in the stamp.
|
|
307
|
+
const spotStamp = position && spotBasis && spotBasis !== "last price" ? scenarioSpotStamp(spotBasis, position.asOf) : null;
|
|
308
|
+
const spotText = position ? `spot ${money(position.spot)}${spotStamp ? ` ${spotStamp}` : ""}` : "";
|
|
309
|
+
const spotTimed = !!spotStamp && spotStamp !== spotBasis;
|
|
302
310
|
// A narrow row keeps the spot and its time before the rest.
|
|
303
311
|
const shortSpotText = position ? `spot ${money(position.spot)} · ${formatSpotTime(live?.observedAt ?? position.asOf)}` : "";
|
|
304
312
|
usePaneFooter("osa", () => ({ info: [
|
|
@@ -307,7 +315,7 @@ export function OptionsScenarioPane({ width, height, focused }: PaneProps) {
|
|
|
307
315
|
...(hedge.error ? [{ id: "hedge-error", parts: [{ text: hedge.error, tone: "warning" as const }] }] : []),
|
|
308
316
|
...(live ? splitDelayedStatus({ id: "asof", parts: [{ text: `${live.basis} · ${spotText} · ${new Date(live.observedAt).toISOString().slice(11, 19)} UTC`, tone: "muted" }],
|
|
309
317
|
variants: [[{ text: shortSpotText, tone: "muted" }]] })
|
|
310
|
-
: position ? [{ id: "asof", parts: [{ text: `${spotText} · ${formatSpotTime(position.asOf)} · ${market?.source ? "market" : "input assumptions"}${midVolatility}`, tone: "muted" as const }],
|
|
318
|
+
: position ? [{ id: "asof", parts: [{ text: `${spotText}${spotTimed ? "" : ` · ${formatSpotTime(position.asOf)}`} · ${market?.source ? "market" : "input assumptions"}${midVolatility}`, tone: "muted" as const }],
|
|
311
319
|
variants: [[{ text: shortSpotText, tone: "muted" as const }]] }] : []),
|
|
312
320
|
], hints }), [hints, position, market?.source, resource.loading, error, hedge.error, live?.basis, live?.observedAt, midVolatility, spotText, shortSpotText]);
|
|
313
321
|
useScenarioEvidence({ scenario, view: tab, loading: !!resource.loading && !scenario, error: error ?? (snapshotErrors.join("; ") || null), notices });
|
|
@@ -337,7 +345,11 @@ export function OptionsScenarioPane({ width, height, focused }: PaneProps) {
|
|
|
337
345
|
tone: cents(scenario.valuation.pnl) >= 0 ? "positive" : "negative" },
|
|
338
346
|
// A spot other than the last price says what it is: the one the quote mids imply, or a typed what-if.
|
|
339
347
|
{ id: "spot", label: "Spot", value: money(scenario.position.spot),
|
|
340
|
-
detail: spotBasis === "implied by option quotes" ? "per share, implied" : spotBasis === "typed" ? "per share, typed"
|
|
348
|
+
detail: spotBasis === "implied by option quotes" ? "per share, implied" : spotBasis === "typed" ? "per share, typed"
|
|
349
|
+
: spotTimed ? `per share, ${spotStamp}` : "per share",
|
|
350
|
+
// The band keeps its columns: the stamp's day, its time, then the stamp give way first.
|
|
351
|
+
...(spotTimed ? { detailVariants: [...scenarioSpotStampVariants(spotBasis!, scenario.position.asOf)
|
|
352
|
+
.map((form) => `per share, ${form}`), "per share"] } : {}) },
|
|
341
353
|
{ id: "value", label: "Value", value: money(scenario.valuation.price), detail: valueUnit },
|
|
342
354
|
{ id: "max-profit", label: "Max profit", value: risk?.unlimitedProfit ? "Unlimited" : money(risk?.maxProfit ?? null) },
|
|
343
355
|
{ id: "max-loss", label: "Max loss", value: risk?.unlimitedLoss ? "Unlimited" : money(risk?.maxLoss ?? null) },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback } from "react";
|
|
1
|
+
import { useCallback, useMemo } from "react";
|
|
2
2
|
import { isAccessDenied } from "../../../api-client/errors";
|
|
3
3
|
import { usePlanAccess } from "../../../api-client/plan-access";
|
|
4
4
|
import type { PerpBoardRow } from "../../../api-client/perps";
|
|
@@ -10,7 +10,9 @@ import { perpEquityIdentity } from "./equity-identity";
|
|
|
10
10
|
import { perpetualListing } from "../../../tickers/perpetual-listing";
|
|
11
11
|
import { loadPerpSelection, loadPerpsEquity } from "./client";
|
|
12
12
|
import { compact, percent, perpDescription, price, readingTime } from "./model";
|
|
13
|
+
import { useLivePerpRows } from "./live-rows";
|
|
13
14
|
import { openPerpLabel, useOpenPerpMarket } from "./open-market";
|
|
15
|
+
import { mergeVenueMarkets } from "./venue-markets";
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* A stock's perpetuals, or for a perpetual market itself its own contract: funding, open interest and when the venue
|
|
@@ -34,9 +36,15 @@ export function PerpEquityRow({ symbol, exchange, instrumentType, maxRows = 3, w
|
|
|
34
36
|
: loadPerpsEquity({ symbol: listingSymbol!, exchange: listingExchange! }, accessKey, force), [marketId, listingSymbol, listingExchange, accessKey]);
|
|
35
37
|
const resource = useAsyncResource(enabled ? loader : null, { clearOnError: isAccessDenied });
|
|
36
38
|
useAutoRefresh(resource.updatedAt, resource.load, { intervalMs: 60_000 });
|
|
37
|
-
|
|
39
|
+
// A stock's contracts one per venue, deepest first, as DES lists them; the ones shown follow the quote stream.
|
|
40
|
+
const fetched = useMemo(() => {
|
|
41
|
+
const rows = resource.data?.payload.rows ?? [];
|
|
42
|
+
return marketId ? rows.filter((row) => !row.delisted && row.marketId === marketId) : mergeVenueMarkets(rows).map((market) => market.primary);
|
|
43
|
+
}, [marketId, resource.data]);
|
|
44
|
+
const shown = useMemo(() => fetched.slice(0, maxRows), [fetched, maxRows]);
|
|
45
|
+
const { rows } = useLivePerpRows(shown, { surface: marketId ? "detail" : "monitor", enabled });
|
|
38
46
|
if (!enabled || !rows.length) return null;
|
|
39
|
-
return <>{rows.
|
|
47
|
+
return <>{rows.map((row) => <PerpRow key={row.marketId} row={row} stale={!!resource.data?.stale} width={width} own={!!marketId} />)}</>;
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
/** The parts that fit `width`, dropped from the end; all of them when the width is not known. */
|
|
@@ -48,18 +48,21 @@ export function fundingNote(rows: readonly Funded[], now = Date.now()): string |
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* How current a view of perpetual markets is: each venue's own newest observation,
|
|
52
|
-
*
|
|
53
|
-
* and the pane footer all read this, so they
|
|
51
|
+
* How current a view of perpetual markets is: each venue's own newest observation, read once a minute (live while
|
|
52
|
+
* every row followed has a price from its venue's socket within the minute) and stale after an hour without a read, and
|
|
53
|
+
* what the funding figures it shows (`funding`) are. The report, the capture and the pane footer all read this, so they
|
|
54
|
+
* end with the same line.
|
|
54
55
|
*/
|
|
55
|
-
export function perpFreshness(rows: readonly Dated[], { funding = [], venue = "all", now = Date.now() }: {
|
|
56
|
+
export function perpFreshness(rows: readonly Dated[], { funding = [], venue = "all", now = Date.now(), live = false }: {
|
|
56
57
|
funding?: readonly Funded[]; venue?: string; now?: number;
|
|
58
|
+
/** Every row followed moves with its venue's socket: the view is a live feed, not the minute's read. */
|
|
59
|
+
live?: boolean;
|
|
57
60
|
} = {}): HeadlessPaneFreshness {
|
|
58
61
|
const sources = venuesOf(rows).map((id) => ({ source: venueName(id), asOf: new Date(Math.max(...rows.filter((row) => row.venue === id)
|
|
59
62
|
.map((row) => Date.parse(row.observedAt)))).toISOString() }));
|
|
60
63
|
const source = sources.length ? sources.map((entry) => entry.source).join(", ") : venue !== "all" ? venueName(venue) : null;
|
|
61
64
|
const note = fundingNote(funding, now);
|
|
62
|
-
return { ...(source ? { source } : {}), sources, status: "delayed", maxAgeMinutes: 60, ...(note ? { note } : {}) };
|
|
65
|
+
return { ...(source ? { source } : {}), sources, status: live ? "live" : "delayed", maxAgeMinutes: 60, ...(note ? { note } : {}) };
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
/** What a capture reads of a row: when it was observed and whether the venue has stopped answering for it. */
|
|
@@ -89,8 +89,10 @@ const aprNote = (rows: readonly PerpBoardRow[]) => {
|
|
|
89
89
|
const requestedOf = (args: HeadlessPaneLoadArgs) => String(Array.isArray(args.argument) ? args.argument.join(" ") : args.argument ?? "").trim();
|
|
90
90
|
// No tab named: a market opens its history, nothing opens the board, as the pane does.
|
|
91
91
|
const tabOf = (args: HeadlessPaneLoadArgs) => PERP_TABS.find((tab) => tab === args.options.tab) ?? openingTab(requestedOf(args));
|
|
92
|
+
// A free account's market opens its latest values under the title, so the title names the function, not the Pro history: a table the free view
|
|
93
|
+
// locks is left out and named on the report's one Pro line (`lockedTable`), never marked on the title over the free ones.
|
|
92
94
|
const TITLES: Record<typeof PERP_TABS[number], string> = { board: "Perpetual markets", rankings: "Perpetual rankings", compare: "Perpetual contracts across venues",
|
|
93
|
-
history: "
|
|
95
|
+
history: "Perpetuals", evidence: "Perpetual evidence" };
|
|
94
96
|
const copy = (rows: readonly PerpBoardRow[]) => rows.map((row) => ({ ...row }));
|
|
95
97
|
const more = (count: number, noun: string) => `${count.toLocaleString("en-US")} more ${noun} need Gloom Pro`;
|
|
96
98
|
// A table the free view leaves empty is locked: the report leaves it out and its one Pro line says what Pro adds.
|
|
@@ -8,6 +8,7 @@ import { useResearchCloudSession } from "../shared/research-cloud-session";
|
|
|
8
8
|
import { perpetualListing } from "../../../tickers/perpetual-listing";
|
|
9
9
|
import { loadPerpSelection, loadPerpsEquities } from "./client";
|
|
10
10
|
import { perpEquityIdentity } from "./equity-identity";
|
|
11
|
+
import { useLivePerpRows } from "./live-rows";
|
|
11
12
|
|
|
12
13
|
const STOCK_TYPES = new Set(["STK", "EQUITY", "STOCK", "COMMON STOCK"]);
|
|
13
14
|
const listingKey = (listing: PerpEquityListing) => `${listing.symbol}:${listing.exchange}`;
|
|
@@ -26,6 +27,7 @@ function rowListing(ticker: TickerRecord): PerpEquityListing | null {
|
|
|
26
27
|
const rowMarket = (ticker: TickerRecord) => perpetualListing(ticker.metadata.ticker, ticker.metadata.exchange)?.marketId ?? null;
|
|
27
28
|
|
|
28
29
|
const NO_PERPETUALS: ListPerpetuals = { markets: new Map(), version: 0, stale: false };
|
|
30
|
+
const NO_SYMBOLS: ReadonlySet<string> = new Set();
|
|
29
31
|
|
|
30
32
|
export interface ListPerpetuals {
|
|
31
33
|
/** Each row's contract by ticker, null for none; a row is missing while its first answer loads. */
|
|
@@ -55,7 +57,7 @@ async function loadOwnMarket(marketId: string, access: string, force: boolean):
|
|
|
55
57
|
* A row's figures never wait on anything else: rows without a stock listing read as no perpetual at once, and a
|
|
56
58
|
* failed or refused lookup leaves every row without one, as DES leaves out its perpetual row.
|
|
57
59
|
*/
|
|
58
|
-
export function useListPerpetuals(tickers: readonly TickerRecord[], enabled: boolean): ListPerpetuals {
|
|
60
|
+
export function useListPerpetuals(tickers: readonly TickerRecord[], enabled: boolean, liveSymbols: ReadonlySet<string> = NO_SYMBOLS): ListPerpetuals {
|
|
59
61
|
const session = useResearchCloudSession();
|
|
60
62
|
const plan = usePlanAccess();
|
|
61
63
|
const accessKey = `${session.requestKey}:${plan.hasProAccess ? "pro" : "preview"}`;
|
|
@@ -98,7 +100,7 @@ export function useListPerpetuals(tickers: readonly TickerRecord[], enabled: boo
|
|
|
98
100
|
useAutoRefresh(resource.updatedAt, resource.load, { intervalMs: 60_000 });
|
|
99
101
|
const versionRef = useRef(0);
|
|
100
102
|
const { data, loading } = resource;
|
|
101
|
-
|
|
103
|
+
const fetched = useMemo(() => {
|
|
102
104
|
if (!enabled) return NO_PERPETUALS;
|
|
103
105
|
const byListing = new Map<string, PerpBoardRow | null>();
|
|
104
106
|
data?.listings.forEach((listing, index) => byListing.set(listingKey(listing), data.results[index]?.market ?? null));
|
|
@@ -112,7 +114,26 @@ export function useListPerpetuals(tickers: readonly TickerRecord[], enabled: boo
|
|
|
112
114
|
// Still loading: the row's cell waits. Otherwise there is nothing to show.
|
|
113
115
|
else if ((!key && !market) || !loading) markets.set(ticker.metadata.ticker, null);
|
|
114
116
|
}
|
|
115
|
-
|
|
116
|
-
return { markets, version: versionRef.current, stale: !!data?.stale };
|
|
117
|
+
return { markets, version: 0, stale: !!data?.stale };
|
|
117
118
|
}, [data, enabled, loading, tickers]);
|
|
119
|
+
// The contracts of the rows in view follow the quote stream, as many as useLivePerpRows follows; each is subscribed
|
|
120
|
+
// once however many rows share it.
|
|
121
|
+
const liveRows = useMemo(() => {
|
|
122
|
+
const rows = new Map<string, PerpBoardRow>();
|
|
123
|
+
for (const symbol of liveSymbols) {
|
|
124
|
+
const row = fetched.markets.get(symbol);
|
|
125
|
+
if (row) rows.set(row.marketId, row);
|
|
126
|
+
}
|
|
127
|
+
return [...rows.values()];
|
|
128
|
+
}, [fetched, liveSymbols]);
|
|
129
|
+
const live = useLivePerpRows(liveRows, { surface: "watchlist", enabled: enabled && liveRows.length > 0 });
|
|
130
|
+
return useMemo(() => {
|
|
131
|
+
if (fetched === NO_PERPETUALS) return NO_PERPETUALS;
|
|
132
|
+
const byMarket = new Map(live.rows.map((row) => [row.marketId, row]));
|
|
133
|
+
const markets = byMarket.size
|
|
134
|
+
? new Map([...fetched.markets].map(([symbol, row]) => [symbol, row ? byMarket.get(row.marketId) ?? row : row]))
|
|
135
|
+
: fetched.markets;
|
|
136
|
+
versionRef.current += 1;
|
|
137
|
+
return { markets, version: versionRef.current, stale: fetched.stale };
|
|
138
|
+
}, [fetched, live.rows]);
|
|
118
139
|
}
|