gloomberb 0.18.3 → 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/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 +84 -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 +22 -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 +21 -4
- 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/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- 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/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- 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 +1117 -264
- 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 +192 -47
- 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 +19 -13
- 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 +24 -18
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +300 -41
- package/src/cli/name-entries.ts +30 -18
- 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 +75 -20
- package/src/cli/pane-functions/catalog.ts +24 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +10 -7
- 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 +24 -11
- package/src/cli/pane-functions/index.ts +18 -16
- 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 +47 -10
- 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 +61 -16
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +111 -22
- 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 +198 -68
- 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 +373 -16
- package/src/components/chart/composite/interactions.ts +7 -2
- 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 +305 -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 +13 -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/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/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 +12 -6
- package/src/components/layout/header.tsx +7 -6
- 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/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/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 +29 -12
- package/src/i18n/ja.ts +29 -12
- package/src/i18n/ko.ts +29 -12
- package/src/i18n/zh-cn.ts +29 -12
- package/src/i18n/zh-tw.ts +29 -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 +29 -19
- 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 +107 -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 +76 -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 +97 -36
- package/src/plugins/builtin/attention/pane.tsx +6 -2
- 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 +6 -3
- 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 +22 -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 +110 -23
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
- 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 +25 -12
- 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/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 +6 -8
- 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 +127 -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 +11 -4
- package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
- 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 +79 -23
- 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 +1 -1
- 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 +5 -3
- 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 +3 -2
- 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/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/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 +18 -11
- 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 +68 -6
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +6 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
- 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 +6 -1
- 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/headless.ts +9 -4
- 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 +13 -1
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +46 -7
- 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/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/headless.ts +1 -1
- package/src/plugins/builtin/insider/signals-client.ts +1 -1
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- 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/headless.ts +4 -4
- 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 +10 -4
- 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 +33 -19
- 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 +29 -8
- 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 +49 -14
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/view.tsx +10 -10
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-scenario/client.ts +123 -28
- 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 +36 -15
- 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 +9 -5
- 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 +143 -59
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
- 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 +4 -1
- 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 +8 -1
- 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/model.ts +6 -2
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -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 +2 -1
- 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-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 +21 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/ticker-surface.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/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 +5 -4
- package/src/plugins/builtin/vol-surface/headless.ts +12 -3
- package/src/plugins/builtin/vol-surface/model.ts +4 -2
- 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/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/styles.css +76 -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/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +46 -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/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 +5 -5
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
- 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 +1 -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 +32 -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/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 +17 -4
- 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 +210 -33
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- 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 +14 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +76 -6
- package/src/types/instrument.ts +3 -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/index.ts +10 -5
- 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-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 +3 -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
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { logFailure } from "../../../utils/log-failure";
|
|
2
|
+
import type { ChartSeriesSpec, ChartSpec, ChartStudySpec } from "../../../time-series/types";
|
|
3
|
+
import { isLeverageFactor } from "../../../time-series/leverage";
|
|
4
|
+
import { priceComparisonSeriesIds } from "../../../time-series/price-comparison";
|
|
5
|
+
import { isUsListingExchange, parsePublicTickerKey } from "../../../utils/exchanges";
|
|
6
|
+
import { MAX_CHART_COMPOSER_SERIES } from "./chart-spec";
|
|
7
|
+
import { buildSeriesSpec, reconcilePanels } from "./chart-spec-edit";
|
|
8
|
+
import { normalizeInstrument } from "./series-expression";
|
|
9
|
+
|
|
10
|
+
/** A fund's daily objective as CMP draws it: `factor` times the index fund `proxy` each session. */
|
|
11
|
+
export interface DailyObjective {
|
|
12
|
+
factor: number;
|
|
13
|
+
proxy: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** What CMP needs of a fund's facts: a daily objective with an index fund to draw it from. */
|
|
17
|
+
export interface LeverageFacts {
|
|
18
|
+
leverage?: { value: number; reset: string; proxy: { ticker: string } | null } | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function dailyObjective(facts: LeverageFacts | null | undefined): DailyObjective | null {
|
|
22
|
+
const leverage = facts?.leverage;
|
|
23
|
+
if (!leverage || leverage.reset !== "daily" || !isLeverageFactor(leverage.value) || !leverage.proxy?.ticker) return null;
|
|
24
|
+
return { factor: leverage.value, proxy: leverage.proxy.ticker.toUpperCase() };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const LEVERAGE_STUDY_PREFIX = "leverage:";
|
|
28
|
+
const DECAY_STUDY_PREFIX = "leverage-decay:";
|
|
29
|
+
|
|
30
|
+
/** The bare ticker a compared leg is of (`TQQQ` for TQQQ:NASDAQ). */
|
|
31
|
+
function legTicker(series: ChartSeriesSpec): string | null {
|
|
32
|
+
return series.source.kind === "security" ? parsePublicTickerKey(series.source.instrument.symbol).symbol.toUpperCase() : null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** A ticker the fund facts read: US-listed, as its symbol is written there (SPY, BRK.B). */
|
|
36
|
+
const US_FUND_TICKER = /^[A-Z][A-Z0-9]{0,5}(?:\.[A-Z])?$/;
|
|
37
|
+
|
|
38
|
+
/** The US-listed tickers of a price comparison, whose facts can say they are leveraged funds. */
|
|
39
|
+
export function comparedFundTickers(spec: ChartSpec): string[] {
|
|
40
|
+
const compared = new Set(priceComparisonSeriesIds(spec) ?? []);
|
|
41
|
+
return [...new Set(spec.series.flatMap((series) => {
|
|
42
|
+
if (!compared.has(series.id) || series.source.kind !== "security") return [];
|
|
43
|
+
const exchange = series.source.instrument.exchange || parsePublicTickerKey(series.source.instrument.symbol).exchange;
|
|
44
|
+
const ticker = legTicker(series);
|
|
45
|
+
return ticker && US_FUND_TICKER.test(ticker) && (!exchange || isUsListingExchange(exchange)) ? [ticker] : [];
|
|
46
|
+
}))];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Whether the chart already draws a fund's objective, as built here or kept from before. */
|
|
50
|
+
function hasLeverageOverlay(spec: ChartSpec): boolean {
|
|
51
|
+
return spec.studies.some((study) => study.kind === "leverage" || study.kind === "leverage-decay");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Whether a report of this chart could draw a daily objective at all: a
|
|
56
|
+
* price comparison without one yet, over daily bars. One session's chart, or
|
|
57
|
+
* bars asked for by the week, month or hour, would only warn that the line
|
|
58
|
+
* needs daily bars, so its legs' facts are not asked for.
|
|
59
|
+
*/
|
|
60
|
+
export function mayDrawDailyObjective(spec: ChartSpec): boolean {
|
|
61
|
+
if (hasLeverageOverlay(spec) || !priceComparisonSeriesIds(spec)) return false;
|
|
62
|
+
if (spec.viewport.range === "1D" && !spec.viewport.dateWindow) return false;
|
|
63
|
+
return spec.viewport.resolution === "auto" || spec.viewport.resolution === "1d";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* A price comparison with each leveraged or inverse fund's daily objective
|
|
68
|
+
* drawn beside it: `factor` times its index fund each session, compounded
|
|
69
|
+
* from where the chart compares (3× daily QQQ beside TQQQ), with the index
|
|
70
|
+
* fund added as a leg when the chart has no room for it otherwise, and the
|
|
71
|
+
* fund's decay against that line and against the factor times the index
|
|
72
|
+
* fund's period return in a Decay panel. Any other chart, or a chart that
|
|
73
|
+
* already draws an objective, is returned as it was.
|
|
74
|
+
*/
|
|
75
|
+
export function withLeverageOverlay(spec: ChartSpec, objectives: ReadonlyMap<string, DailyObjective>): ChartSpec {
|
|
76
|
+
const compared = priceComparisonSeriesIds(spec);
|
|
77
|
+
if (!compared || hasLeverageOverlay(spec) || objectives.size === 0) return spec;
|
|
78
|
+
const series = [...spec.series];
|
|
79
|
+
const studies: ChartStudySpec[] = [...spec.studies];
|
|
80
|
+
for (const fund of spec.series.filter((entry) => compared.includes(entry.id))) {
|
|
81
|
+
const objective = objectives.get(legTicker(fund) ?? "");
|
|
82
|
+
if (!objective || fund.source.kind !== "security") continue;
|
|
83
|
+
// A compared leg of the index fund, or the one added for another fund (TQQQ and SQQQ share QQQ).
|
|
84
|
+
let index = series.find((entry) => legTicker(entry) === objective.proxy && (compared.includes(entry.id) || !spec.series.includes(entry)));
|
|
85
|
+
if (!index) {
|
|
86
|
+
const instrument = normalizeInstrument(objective.proxy, true);
|
|
87
|
+
if (!instrument || series.length >= MAX_CHART_COMPOSER_SERIES) continue;
|
|
88
|
+
index = buildSeriesSpec({ kind: "security", ...instrument, fieldId: fund.source.fieldId }, series.length, {
|
|
89
|
+
style: fund.style, transform: fund.transform, axis: fund.axis, panelId: fund.panelId,
|
|
90
|
+
});
|
|
91
|
+
series.push(index);
|
|
92
|
+
}
|
|
93
|
+
const parameters = { factor: objective.factor };
|
|
94
|
+
studies.push(
|
|
95
|
+
{ id: `${LEVERAGE_STUDY_PREFIX}${fund.id}`, kind: "leverage", inputSeriesIds: [index.id], parameters, panelId: fund.panelId, axis: "left" },
|
|
96
|
+
{ id: `${DECAY_STUDY_PREFIX}${fund.id}`, kind: "leverage-decay", inputSeriesIds: [fund.id, index.id], parameters, panelId: "decay", axis: "auto" },
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
if (studies.length === spec.studies.length) return spec;
|
|
100
|
+
return { ...spec, series, studies, panels: reconcilePanels(spec.panels, series, studies) };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** How long a comparison waits for its legs' fund facts before it is charted without objectives. */
|
|
104
|
+
const DAILY_OBJECTIVES_TIMEOUT_MS = 2_500;
|
|
105
|
+
/** A pane draws its chart meanwhile and adds the objectives when they come. */
|
|
106
|
+
export const LEVERAGE_FACTS_PANE_TIMEOUT_MS = 15_000;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Each compared fund's daily objective, from its facts. A fund whose facts
|
|
110
|
+
* fail to load, or are not in by `timeoutMs`, is charted without one: the
|
|
111
|
+
* comparison never waits long on them. The reads still running then are
|
|
112
|
+
* aborted through the signal `loadFacts` is given, as they are when `signal`
|
|
113
|
+
* (the caller's) aborts.
|
|
114
|
+
*/
|
|
115
|
+
export async function loadDailyObjectives(
|
|
116
|
+
tickers: readonly string[],
|
|
117
|
+
loadFacts: (ticker: string, signal: AbortSignal) => Promise<LeverageFacts | null>,
|
|
118
|
+
{ timeoutMs = DAILY_OBJECTIVES_TIMEOUT_MS, signal }: { timeoutMs?: number; signal?: AbortSignal } = {},
|
|
119
|
+
): Promise<Map<string, DailyObjective>> {
|
|
120
|
+
const objectives = new Map<string, DailyObjective>();
|
|
121
|
+
if (tickers.length === 0) return objectives;
|
|
122
|
+
const deadline = new AbortController();
|
|
123
|
+
const expired = new Promise<null>((resolve) => deadline.signal.addEventListener("abort", () => resolve(null), { once: true }));
|
|
124
|
+
const timer = setTimeout(() => deadline.abort(new DOMException("Fund facts took too long.", "TimeoutError")), timeoutMs);
|
|
125
|
+
const cancel = () => deadline.abort(signal?.reason);
|
|
126
|
+
if (signal?.aborted) cancel();
|
|
127
|
+
else signal?.addEventListener("abort", cancel, { once: true });
|
|
128
|
+
try {
|
|
129
|
+
await Promise.all(tickers.map(async (ticker) => {
|
|
130
|
+
const facts = await Promise.race([loadFacts(ticker, deadline.signal).catch(logFailure("chart-composer.leverage-overlay", "Load chart fund objective failed", null)), expired]);
|
|
131
|
+
const objective = dailyObjective(facts);
|
|
132
|
+
// An index fund charted beside its leveraged fund is not leveraged itself.
|
|
133
|
+
if (objective && objective.proxy !== ticker) objectives.set(ticker, objective);
|
|
134
|
+
}));
|
|
135
|
+
} finally {
|
|
136
|
+
clearTimeout(timer);
|
|
137
|
+
signal?.removeEventListener("abort", cancel);
|
|
138
|
+
// Reads still running are no longer waited for.
|
|
139
|
+
deadline.abort();
|
|
140
|
+
}
|
|
141
|
+
return objectives;
|
|
142
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../../utils/log-failure";
|
|
1
2
|
import { FINANCIAL_VINTAGE_NOTICE, SEC_EPS_BASIS_NOTICE } from "../../../utils/financial-statements";
|
|
2
3
|
import { usePaneSharePreparation } from "../../../shares/prepare";
|
|
3
4
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -26,10 +27,13 @@ import type { PaneProps, TickerResearchTabProps } from "../../../types/plugin";
|
|
|
26
27
|
import type { ChartResolution, TimeRange } from "../../../components/chart/core/types";
|
|
27
28
|
import type { ChartSpec, ResolvedSeries } from "../../../time-series/types";
|
|
28
29
|
import {
|
|
29
|
-
|
|
30
|
+
getSupportedChartBarSizesForViewport,
|
|
30
31
|
isIntradayResolution,
|
|
32
|
+
parseChartBarSize,
|
|
33
|
+
type ChartBarSize,
|
|
31
34
|
type ManualChartResolution,
|
|
32
35
|
} from "../../../time-series/resolution";
|
|
36
|
+
import { futuresSessionOpenMinute } from "../../../market-data/market/trading-sessions";
|
|
33
37
|
import { useResolvedChartSpec } from "../../../time-series/hooks";
|
|
34
38
|
import { shortCompanyName } from "../../../tickers/company-name";
|
|
35
39
|
import { useSeriesListings } from "./series-listings";
|
|
@@ -52,13 +56,17 @@ import { colors } from "../../../theme/colors";
|
|
|
52
56
|
import { isUsListingExchange, parsePublicTickerKey, publicTickerKey } from "../../../utils/exchanges";
|
|
53
57
|
import { isMarketFieldId } from "../../../time-series/field-catalog";
|
|
54
58
|
import { isDatasetChart } from "../../../time-series/spec";
|
|
59
|
+
import { seriesMessageName, studyMessageName } from "../../../time-series/series-name";
|
|
55
60
|
import { CHART_COMPOSER_PANE_ID } from "../../../types/config";
|
|
56
61
|
import { useRemoteUiNode } from "../../../remote/semantic-tree";
|
|
57
62
|
import { SeriesEditorDialog } from "./editor";
|
|
58
63
|
import { chartComposerSemanticMetadata } from "./semantic";
|
|
64
|
+
import { comparedFundTickers, LEVERAGE_FACTS_PANE_TIMEOUT_MS, loadDailyObjectives, withLeverageOverlay } from "./leverage-overlay";
|
|
65
|
+
import { loadFundFacts } from "../sec/fund-facts";
|
|
59
66
|
import {
|
|
60
67
|
canToggleChartSeries,
|
|
61
68
|
CHART_INTERACTION_VIEWPORT_SETTING_KEY,
|
|
69
|
+
CHART_LEVERAGE_PENDING_SETTING_KEY,
|
|
62
70
|
CHART_PINNED_MOMENT_SETTING_KEY,
|
|
63
71
|
CHART_SPEC_SETTING_KEY,
|
|
64
72
|
parseChartInteractionViewport,
|
|
@@ -106,11 +114,13 @@ import { buildEmptyChartPreset, buildPriceChartPreset } from "./presets";
|
|
|
106
114
|
import type { ChartInteractionViewport } from "./chart-spec";
|
|
107
115
|
import {
|
|
108
116
|
CHART_FORMULA_OPTIONS,
|
|
117
|
+
CHART_BAR_SIZE_PRESETS,
|
|
109
118
|
CHART_RANGES as RANGES,
|
|
110
|
-
CHART_RESOLUTIONS
|
|
119
|
+
CHART_RESOLUTIONS,
|
|
111
120
|
chartStudyOptionsFor,
|
|
112
121
|
chartStudyPeriodTitle,
|
|
113
122
|
chartStudySettingLabel,
|
|
123
|
+
withChartBarSize,
|
|
114
124
|
} from "./settings";
|
|
115
125
|
import { resolveChartComposerShortcut } from "./shortcuts";
|
|
116
126
|
import { describeChartResolution, formatChartDateWindow, formatChartResolution } from "./viewport-labels";
|
|
@@ -134,6 +144,9 @@ import { CHART_FOLLOW_SERIES_SETTING_KEY, rebindFollowChartSpec, resolveFollowSe
|
|
|
134
144
|
import type { InstrumentRef } from "../../../market-data/request-types";
|
|
135
145
|
|
|
136
146
|
const RANGE_OPTIONS = RANGES.map((range, index) => ({ label: range, value: range, hint: String(index + 1) }));
|
|
147
|
+
const SOURCE_BAR_SIZES = CHART_RESOLUTIONS.filter((value): value is ManualChartResolution => value !== "auto");
|
|
148
|
+
/** The bar size dialog's last choice, which asks for a size to type. */
|
|
149
|
+
const CUSTOM_BAR_SIZE_CHOICE = "custom";
|
|
137
150
|
const AUTO_VIEWPORT_DEBOUNCE_MS = 350;
|
|
138
151
|
/** A load for a moving view that has not answered in this long no longer holds the next one back. */
|
|
139
152
|
const LOAD_AHEAD_TIMEOUT_MS = 4_000;
|
|
@@ -379,28 +392,46 @@ function ChartComposerSurface({
|
|
|
379
392
|
const hasMarketSeries = spec.series.some((entry) => (
|
|
380
393
|
entry.source.kind === "security" && isMarketFieldId(entry.source.fieldId)
|
|
381
394
|
));
|
|
382
|
-
|
|
395
|
+
// Bars built from a future's clock-aligned bars must not straddle its session's open.
|
|
396
|
+
const openMinute = useMemo(() => {
|
|
397
|
+
const listing = spec.series.find((entry) => entry.source.kind === "security" && isMarketFieldId(entry.source.fieldId));
|
|
398
|
+
return listing?.source.kind === "security" ? futuresSessionOpenMinute(listing.source.instrument.symbol, listing.source.instrument.exchange) : null;
|
|
399
|
+
}, [spec.series]);
|
|
400
|
+
// The sizes of `sizes` this chart can draw now, after Auto.
|
|
401
|
+
const availableOf = useCallback((sizes: readonly ChartBarSize[]): ChartResolution[] => {
|
|
383
402
|
if (!resolution.resolutionSupport) {
|
|
384
403
|
if (!hasMarketSeries) return ["auto"];
|
|
385
|
-
if (!resolution.loading) return
|
|
404
|
+
if (!resolution.loading) return ["auto", ...sizes];
|
|
386
405
|
return spec.viewport.resolution === "auto"
|
|
387
406
|
? ["auto"]
|
|
388
407
|
: ["auto", spec.viewport.resolution];
|
|
389
408
|
}
|
|
390
|
-
|
|
409
|
+
return ["auto", ...getSupportedChartBarSizesForViewport(
|
|
391
410
|
spec.viewport.range,
|
|
392
411
|
resolution.resolutionSupport,
|
|
412
|
+
sizes,
|
|
393
413
|
spec.viewport.dateWindow,
|
|
394
|
-
|
|
395
|
-
|
|
414
|
+
openMinute,
|
|
415
|
+
)];
|
|
396
416
|
}, [
|
|
397
417
|
hasMarketSeries,
|
|
418
|
+
openMinute,
|
|
398
419
|
resolution.loading,
|
|
399
420
|
resolution.resolutionSupport,
|
|
400
421
|
spec.viewport.dateWindow,
|
|
401
422
|
spec.viewport.range,
|
|
402
423
|
spec.viewport.resolution,
|
|
403
424
|
]);
|
|
425
|
+
// The bar lists the sizes sources serve, and a built one (4h) while the chart is set to it;
|
|
426
|
+
// the bar size dialog (b) lists the built ones too, and takes any other typed in.
|
|
427
|
+
const availableResolutions = useMemo(
|
|
428
|
+
() => availableOf(withChartBarSize(SOURCE_BAR_SIZES, spec.viewport.resolution)),
|
|
429
|
+
[availableOf, spec.viewport.resolution],
|
|
430
|
+
);
|
|
431
|
+
const dialogResolutions = useMemo(
|
|
432
|
+
() => availableOf(withChartBarSize(CHART_BAR_SIZE_PRESETS, spec.viewport.resolution)),
|
|
433
|
+
[availableOf, spec.viewport.resolution],
|
|
434
|
+
);
|
|
404
435
|
// Auto names the bars it is on, which change as the view moves: a pan back
|
|
405
436
|
// past where a source keeps 30-minute bars charts days instead.
|
|
406
437
|
const autoBars = spec.viewport.resolution === "auto" ? resolution.resolution ?? null : null;
|
|
@@ -474,7 +505,15 @@ function ChartComposerSurface({
|
|
|
474
505
|
() => listingRef.current,
|
|
475
506
|
[freshListing?.seriesId, freshListing?.key, freshListing?.target.symbol, freshListing?.target.exchange],
|
|
476
507
|
);
|
|
508
|
+
// The ticket's levels (its draft and working orders) move through the ticket, which reviews any change.
|
|
509
|
+
const tradeRef = useRef(trade);
|
|
510
|
+
tradeRef.current = trade;
|
|
477
511
|
const editLevels = useCallback((edit: CompositeLevelEdit) => {
|
|
512
|
+
const ticket = tradeRef.current;
|
|
513
|
+
if (ticket?.levels.some((level) => level.id === edit.id)) {
|
|
514
|
+
if (edit.kind === "move") ticket.moveLevel?.(edit.id, edit.value);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
478
517
|
const key = listingRef.current?.key;
|
|
479
518
|
if (!key) return;
|
|
480
519
|
setLevelStore((current: unknown) => {
|
|
@@ -578,7 +617,7 @@ function ChartComposerSurface({
|
|
|
578
617
|
]}
|
|
579
618
|
/>
|
|
580
619
|
),
|
|
581
|
-
}).catch((
|
|
620
|
+
}).catch(logFailure("chart-composer.pane", "Open VWAP anchor choices failed"));
|
|
582
621
|
if (choice === "pick") {
|
|
583
622
|
pickAnchorAfterDialogRef.current = true;
|
|
584
623
|
return { close: true };
|
|
@@ -594,7 +633,7 @@ function ChartComposerSurface({
|
|
|
594
633
|
content: (ctx: PromptContext<string>) => (
|
|
595
634
|
<TextPromptDialog {...ctx} title="Anchor VWAP at" placeholder="2026-09-30 or 2026-09-30 10:00" confirmLabel="Anchor" width={44} />
|
|
596
635
|
),
|
|
597
|
-
}).catch((
|
|
636
|
+
}).catch(logFailure("chart-composer.pane", "Open VWAP date prompt failed"));
|
|
598
637
|
if (!text) return;
|
|
599
638
|
const anchor = parseVwapAnchor(text, anchorInputRef.current);
|
|
600
639
|
if (anchor === null) {
|
|
@@ -661,6 +700,11 @@ function ChartComposerSurface({
|
|
|
661
700
|
},
|
|
662
701
|
onCancel: () => setPickingAnchor(false),
|
|
663
702
|
} : null, [pickingAnchor, updateSpec]);
|
|
703
|
+
// The ticket beside the chart asks for a price: a press on the plot, or Enter at the cursor, sets it.
|
|
704
|
+
const tradeOnChart = !!trade && !!listing && researchTradeMatches(trade, { ...listing.instrument, exchange: listing.target.exchange });
|
|
705
|
+
const pricePick = useMemo(() => tradeOnChart && trade?.picking && trade.finishPick && trade.cancelPick ? {
|
|
706
|
+
label: `set ${trade.picking.label}`, onPick: trade.finishPick, onCancel: trade.cancelPick,
|
|
707
|
+
} : null, [tradeOnChart, trade?.picking, trade?.finishPick, trade?.cancelPick]);
|
|
664
708
|
const formulasDialogRef = useRef<MultiSelectDialogButtonHandle | null>(null);
|
|
665
709
|
const indicatorsDisabled = !isPriceStudyTarget(spec);
|
|
666
710
|
const formulasDisabled = spec.series.filter((series) => series.visible !== false).length < 2;
|
|
@@ -830,7 +874,7 @@ function ChartComposerSurface({
|
|
|
830
874
|
content: (context: PromptContext<ChartSpec | null>) => (
|
|
831
875
|
<SeriesEditorDialog {...context} initialSpec={spec} />
|
|
832
876
|
),
|
|
833
|
-
}).catch((
|
|
877
|
+
}).catch(logFailure("chart-composer.pane", "Open chart series editor failed", null));
|
|
834
878
|
if (next) setSpec(next);
|
|
835
879
|
} finally {
|
|
836
880
|
setInteractionCaptured("prompt", false);
|
|
@@ -871,23 +915,57 @@ function ChartComposerSurface({
|
|
|
871
915
|
content: (context: PromptContext<string>) => (
|
|
872
916
|
<ChoiceDialog
|
|
873
917
|
{...context}
|
|
874
|
-
title="
|
|
918
|
+
title="Bar Size"
|
|
875
919
|
selectedChoiceId={spec.viewport.resolution}
|
|
876
|
-
choices={
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
920
|
+
choices={[
|
|
921
|
+
...dialogResolutions.map((value) => ({
|
|
922
|
+
id: value,
|
|
923
|
+
label: formatChartResolution(value),
|
|
924
|
+
description: describeChartResolution(value),
|
|
925
|
+
})),
|
|
926
|
+
...(hasMarketSeries ? [{ id: CUSTOM_BAR_SIZE_CHOICE, label: "Custom…", description: "Type any number of minutes, hours, days, weeks or months." }] : []),
|
|
927
|
+
]}
|
|
881
928
|
/>
|
|
882
929
|
),
|
|
883
|
-
}).catch((
|
|
884
|
-
if (
|
|
930
|
+
}).catch(logFailure("chart-composer.pane", "Open chart bar size choices failed", ""));
|
|
931
|
+
if (next === CUSTOM_BAR_SIZE_CHOICE) {
|
|
932
|
+
// A row picked with the mouse closes on mousedown; the field opens after the
|
|
933
|
+
// click has placed the focus, or the desktop leaves it on the dialog.
|
|
934
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
935
|
+
const typed = await dialog.prompt<string>({
|
|
936
|
+
content: (ctx: PromptContext<string>) => (
|
|
937
|
+
<TextPromptDialog {...ctx} title="Custom Bar Size" placeholder="10m, 90m, 4h, 2D, 3W, 6mo" confirmLabel="Chart" width={44} />
|
|
938
|
+
),
|
|
939
|
+
}).catch(logFailure("chart-composer.pane", "Open custom chart bar size prompt failed"));
|
|
940
|
+
if (!typed) return;
|
|
941
|
+
const size = parseChartBarSize(typed);
|
|
942
|
+
const count = /^\s*(\d+)\s*M\s*$/.exec(typed)?.[1];
|
|
943
|
+
if (!size) {
|
|
944
|
+
notify({
|
|
945
|
+
body: count
|
|
946
|
+
? `Write ${count}m for ${count} minutes or ${count}mo for ${count} months.`
|
|
947
|
+
: `${typed} is not a bar size. Use a number and a unit: 10m, 4h, 2D, 3W, 6mo; up to a day of minutes or hours, a year of days or weeks, or 12 months.`,
|
|
948
|
+
type: "error",
|
|
949
|
+
});
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (!availableOf(withChartBarSize([], size)).includes(size)) {
|
|
953
|
+
notify({ body: `${formatChartResolution(size)} bars are unavailable for this range.`, type: "error" });
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
setResolution(size);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
if (dialogResolutions.includes(next as ChartResolution)) setResolution(next as ChartResolution);
|
|
885
960
|
} finally {
|
|
886
961
|
setInteractionCaptured("prompt", false);
|
|
887
962
|
}
|
|
888
963
|
}, [
|
|
889
|
-
|
|
964
|
+
availableOf,
|
|
890
965
|
dialog,
|
|
966
|
+
dialogResolutions,
|
|
967
|
+
hasMarketSeries,
|
|
968
|
+
notify,
|
|
891
969
|
setInteractionCaptured,
|
|
892
970
|
setResolution,
|
|
893
971
|
spec.viewport.resolution,
|
|
@@ -923,7 +1001,7 @@ function ChartComposerSurface({
|
|
|
923
1001
|
void openSeriesEditor();
|
|
924
1002
|
return;
|
|
925
1003
|
case "resolution":
|
|
926
|
-
if (
|
|
1004
|
+
if (dialogResolutions.length > 1) void openResolutionPicker();
|
|
927
1005
|
}
|
|
928
1006
|
}, { enabled: focused && !dialogOpen });
|
|
929
1007
|
|
|
@@ -936,13 +1014,13 @@ function ChartComposerSurface({
|
|
|
936
1014
|
const loading = resolution.loading || listings.pending;
|
|
937
1015
|
// A bare code several companies list asks which, as `quote` does, before anything else is said.
|
|
938
1016
|
const statusError = listings.errors[0] ?? resolution.errors[0];
|
|
939
|
-
// A spread or formula error names its legs and their units; the study's
|
|
1017
|
+
// A spread or formula error names its legs and their units; the study's name adds nothing to it.
|
|
940
1018
|
const formulaStudy = spec.studies.find((study) => (study.kind === "spread" || study.kind === "formula")
|
|
941
|
-
&& statusError?.startsWith(`${study
|
|
942
|
-
const statusErrorNotice = formulaStudy ? statusError?.slice(`${formulaStudy
|
|
943
|
-
// Failed series
|
|
944
|
-
const errorSeries = spec.series.find((entry) => statusError?.startsWith(`${entry
|
|
945
|
-
const errorMessage = errorSeries ? statusError?.slice(`${errorSeries
|
|
1019
|
+
&& statusError?.startsWith(`${studyMessageName(study)}: `));
|
|
1020
|
+
const statusErrorNotice = formulaStudy ? statusError?.slice(`${studyMessageName(formulaStudy)}: `.length) : statusError;
|
|
1021
|
+
// Failed series name what was asked for in errors and their display label in warnings.
|
|
1022
|
+
const errorSeries = spec.series.find((entry) => statusError?.startsWith(`${seriesMessageName(entry)}: `));
|
|
1023
|
+
const errorMessage = errorSeries ? statusError?.slice(`${seriesMessageName(errorSeries)}: `.length) : undefined;
|
|
946
1024
|
// The label the resolver wrote its warnings with, before the legend named the company.
|
|
947
1025
|
const errorSeriesLabel = (resolution.legendSeries?.find((entry) => entry.id === errorSeries?.id)
|
|
948
1026
|
?? legendSeries?.find((entry) => entry.id === errorSeries?.id))?.label;
|
|
@@ -965,9 +1043,9 @@ function ChartComposerSurface({
|
|
|
965
1043
|
&& !FORWARD_VALUATION_BASIS_NOTICES.has(warning)
|
|
966
1044
|
&& !duplicateErrorNotices.has(warning) && !comparisonEmptyNotices.has(warning)
|
|
967
1045
|
&& !spec.studies.some((study) => (
|
|
968
|
-
(study.kind === "ratio" && warning.startsWith(`${study
|
|
1046
|
+
(study.kind === "ratio" && warning.startsWith(`${studyMessageName(study)}: ratio inputs use different currencies (`)
|
|
969
1047
|
&& warning.endsWith("); raw values are not FX-converted."))
|
|
970
|
-
|| (study.kind === "correlation" && warning.startsWith(`${study
|
|
1048
|
+
|| (study.kind === "correlation" && warning.startsWith(`${studyMessageName(study)}: correlation mixes `)
|
|
971
1049
|
&& warning.endsWith("; only matching observation times contribute."))
|
|
972
1050
|
))
|
|
973
1051
|
));
|
|
@@ -1192,6 +1270,7 @@ function ChartComposerSurface({
|
|
|
1192
1270
|
onToggleSeries={toggleSeries}
|
|
1193
1271
|
isSeriesToggleable={isSeriesToggleable}
|
|
1194
1272
|
timePick={timePick}
|
|
1273
|
+
pricePick={pricePick}
|
|
1195
1274
|
levels={chartLevels}
|
|
1196
1275
|
emptyMessage={emptyMessage}
|
|
1197
1276
|
emptyDetail={emptyDetail}
|
|
@@ -1287,6 +1366,26 @@ export function ChartComposerPane({ paneId, focused, width, height }: PaneProps)
|
|
|
1287
1366
|
savedForTarget.current = targetKey;
|
|
1288
1367
|
}
|
|
1289
1368
|
}, [follows, ownedIds, savedIds, setSpec, spec, stored, target, unlinkedFrom, updateSettings]);
|
|
1369
|
+
// A comparison CMP opened draws each leveraged or inverse fund's daily objective once its facts are read.
|
|
1370
|
+
const leveragePending = instance?.settings?.[CHART_LEVERAGE_PENDING_SETTING_KEY] === true;
|
|
1371
|
+
const storedRef = useRef(stored);
|
|
1372
|
+
storedRef.current = stored;
|
|
1373
|
+
useEffect(() => {
|
|
1374
|
+
if (!leveragePending) return;
|
|
1375
|
+
const mounted = new AbortController();
|
|
1376
|
+
// The chart draws meanwhile, so it can wait longer for them than a report does.
|
|
1377
|
+
void loadDailyObjectives(comparedFundTickers(storedRef.current),
|
|
1378
|
+
async (ticker, signal) => (await loadFundFacts(ticker, false, { signal })).payload,
|
|
1379
|
+
{ timeoutMs: LEVERAGE_FACTS_PANE_TIMEOUT_MS, signal: mounted.signal })
|
|
1380
|
+
.then((objectives) => {
|
|
1381
|
+
if (mounted.signal.aborted) return;
|
|
1382
|
+
updateSettings({
|
|
1383
|
+
[CHART_SPEC_SETTING_KEY]: withLeverageOverlay(storedRef.current, objectives),
|
|
1384
|
+
[CHART_LEVERAGE_PENDING_SETTING_KEY]: undefined,
|
|
1385
|
+
});
|
|
1386
|
+
});
|
|
1387
|
+
return () => mounted.abort();
|
|
1388
|
+
}, [leveragePending, updateSettings]);
|
|
1290
1389
|
if (follows && !target && ownedIds.length > 0) {
|
|
1291
1390
|
return <EmptyState title={error ?? "Select a ticker."} />;
|
|
1292
1391
|
}
|
|
@@ -391,6 +391,7 @@ function catalogFormula(expression: string): boolean {
|
|
|
391
391
|
try {
|
|
392
392
|
return parseFormulaExpression(expression) !== null;
|
|
393
393
|
} catch {
|
|
394
|
+
// Intentional ignore: invalid catalog formulas are excluded from the chartable suggestions.
|
|
394
395
|
return false;
|
|
395
396
|
}
|
|
396
397
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { futuresGenericCaption, futuresGenericListing } from "../../../utils/futures-generic";
|
|
2
|
+
import { isIsoCurrencyCode } from "../../../utils/crypto-pair";
|
|
3
|
+
import { readTerminalListingCode } from "../../../tickers/terminal-codes";
|
|
2
4
|
import type { ChartSeriesSpec, SeriesStyle, SeriesTransform } from "../../../time-series/types";
|
|
3
5
|
import {
|
|
4
6
|
canonicalTimeSeriesFieldId,
|
|
@@ -164,21 +166,78 @@ export function parseSeriesExpression(value: string): ParsedSeriesExpression | n
|
|
|
164
166
|
|
|
165
167
|
const SERIES_FORMS = "Use SYMBOL, SYMBOL:field, FUT:code, UST:maturity, FRED:series, GEO:series, or CAP:capability-id:series-id.";
|
|
166
168
|
|
|
169
|
+
/** A word that reads as a series, not an operator or a number of a formula. */
|
|
170
|
+
const LIST_WORD = /^[A-Za-z^][\w.^=:/~-]*$/;
|
|
171
|
+
|
|
172
|
+
/** The words that close a Bloomberg security (`AAPL US Equity`, `EURUSD Curncy`), and its exchange code `US`. */
|
|
173
|
+
const BLOOMBERG_WORDS = new Set(["EQUITY", "INDEX", "CURNCY", "COMDTY", "GOVT", "CORP", "MTGE", "MUNI", "PFD"]);
|
|
174
|
+
|
|
175
|
+
/** Why words typed with spaces between them are no list of series, when they are not: what to say, if anything. */
|
|
176
|
+
interface NotAList {
|
|
177
|
+
hint?: string;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Words with spaces between them that are one thing and not tickers side by
|
|
182
|
+
* side: a Bloomberg security, a currency pair, or a series whose field has
|
|
183
|
+
* spaces in it (`MSFT:net income`). Charting each word would draw series
|
|
184
|
+
* nobody asked for, so these are errors, with a hint where one helps.
|
|
185
|
+
*/
|
|
186
|
+
function notAList(words: readonly string[]): NotAList | null {
|
|
187
|
+
if (words.some((word, index) => BLOOMBERG_WORDS.has(word.toUpperCase()) || (index > 0 && word.toUpperCase() === "US"))) {
|
|
188
|
+
const code = readTerminalListingCode(words.join(" "));
|
|
189
|
+
return { hint: code ? ` That is a Bloomberg code: write it ${code.key}.` : " That is a Bloomberg security: write the ticker alone (AAPL), or with its exchange (AAPL:NASDAQ)." };
|
|
190
|
+
}
|
|
191
|
+
if (words.length === 2 && words.every((word) => /^[A-Za-z]{3}$/.test(word) && isIsoCurrencyCode(word.toUpperCase()))) {
|
|
192
|
+
const [base, quote] = words.map((word) => word.toUpperCase());
|
|
193
|
+
return { hint: ` ${base} ${quote} reads as a currency pair: write it ${base}/${quote}, or separate tickers with commas.` };
|
|
194
|
+
}
|
|
195
|
+
return words.some((word, index) => word.includes(":") && spacedField(words, index)) ? {} : null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Whether the words from `start` on, joined, are one series whose field has spaces in it (`MSFT:net income`). */
|
|
199
|
+
function spacedField(words: readonly string[], start: number): boolean {
|
|
200
|
+
for (let end = start + 2; end <= words.length; end += 1) {
|
|
201
|
+
if (parseSeriesExpression(words.slice(start, end).join(" "))) return true;
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* One leg of a list: a series, or series typed with spaces between them
|
|
208
|
+
* (`AAPL MSFT`, as `fn G AAPL MSFT` passes them), each word a series of its
|
|
209
|
+
* own. Null when it is neither.
|
|
210
|
+
*/
|
|
211
|
+
function parseLeg(leg: string): ParsedSeriesExpression[] | null {
|
|
212
|
+
const parsed = parseSeriesExpression(leg);
|
|
213
|
+
if (parsed) return [parsed];
|
|
214
|
+
const words = leg.trim().split(/\s+/);
|
|
215
|
+
if (words.length < 2 || notAList(words)) return null;
|
|
216
|
+
const series = words.map(parseSeriesExpression);
|
|
217
|
+
return series.every((entry): entry is ParsedSeriesExpression => entry != null) ? series : null;
|
|
218
|
+
}
|
|
219
|
+
|
|
167
220
|
export function parseChartExpression(value: string): ParsedSeriesExpression[] {
|
|
168
221
|
if (!value.trim()) return [];
|
|
169
222
|
// A list pasted with a stray separator (`BRK.B,SPY,`, `,SPY`, `A,,B`) has no series between them.
|
|
170
223
|
const legs = value.split(/[;,\n]/).filter((leg) => leg.trim());
|
|
171
224
|
// Separators alone name no series at all.
|
|
172
225
|
if (legs.length === 0) throw new Error(`Invalid chart series "${value.trim()}": no series between its separators. ${SERIES_FORMS}`);
|
|
173
|
-
if (legs.length > MAX_CHART_COMPOSER_SERIES) {
|
|
174
|
-
throw new Error(`Charts support up to ${MAX_CHART_COMPOSER_SERIES} base series.`);
|
|
175
|
-
}
|
|
176
226
|
|
|
177
|
-
|
|
178
|
-
const parsed =
|
|
227
|
+
const series = legs.flatMap((leg) => {
|
|
228
|
+
const parsed = parseLeg(leg);
|
|
179
229
|
if (parsed) return parsed;
|
|
180
|
-
|
|
230
|
+
// Words with spaces between them that are not all series: a list is written with commas.
|
|
231
|
+
const words = leg.trim().split(/\s+/);
|
|
232
|
+
const reason = words.length > 1 ? notAList(words) : null;
|
|
233
|
+
const listHint = reason ? reason.hint ?? ""
|
|
234
|
+
: words.length > 1 && words.every((word) => LIST_WORD.test(word)) ? ` Separate series with commas: ${words.join(",")}.` : "";
|
|
235
|
+
throw new Error(`Invalid chart series "${leg.trim()}".${listHint} ${SERIES_FORMS}`);
|
|
181
236
|
});
|
|
237
|
+
if (series.length > MAX_CHART_COMPOSER_SERIES) {
|
|
238
|
+
throw new Error(`Charts support up to ${MAX_CHART_COMPOSER_SERIES} base series.`);
|
|
239
|
+
}
|
|
240
|
+
return series;
|
|
182
241
|
}
|
|
183
242
|
|
|
184
243
|
export function formatSeriesExpression(series: ChartSeriesSpec): string {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../../utils/log-failure";
|
|
1
2
|
import type { DataProvider, MarketDataRequestContext } from "../../../types/data-provider";
|
|
2
3
|
import type { PricePoint, Quote } from "../../../types/financials";
|
|
3
4
|
import type { TimeRange } from "../../../time-series/range";
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
import { parsePublicTickerKey, resolveExchangeTimeZone } from "../../../utils/exchanges";
|
|
11
12
|
import { listingSuffixExchange } from "../../../sources/listing-symbols";
|
|
12
13
|
import { getPricePointTimestamp } from "../../../utils/price-history";
|
|
14
|
+
import { dateOptionError, readCalendarDate } from "../../../utils/calendar-date";
|
|
13
15
|
import { pricePointIntegrity } from "../../../utils/price-history-integrity";
|
|
14
16
|
import { zonedDateKey, zonedWallClockToUtcMs } from "../../../utils/zoned-date-time";
|
|
15
17
|
import { fetchHistoryResult } from "../../../sources/history-result";
|
|
@@ -46,28 +48,22 @@ export interface LoadedIntradayWindow extends IntradayWindow {
|
|
|
46
48
|
sourceKey?: string;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
const DATE_ONLY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
50
51
|
const HISTORICAL_RETRY_DELAY_MS = 61 * 60_000;
|
|
51
52
|
const DAY_MS = 24 * 60 * 60_000;
|
|
52
53
|
|
|
54
|
+
/** `--session` as YYYY-MM-DD: any date a date option reads, or an error that lists the formats. */
|
|
55
|
+
function readSessionDate(value: string): string {
|
|
56
|
+
const date = readCalendarDate(value);
|
|
57
|
+
if (!date) throw new Error(`Invalid --session value "${value}". ${dateOptionError(value, "--session", { subject: "a session date" })}`);
|
|
58
|
+
return date;
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
function parseSessionDate(value: string): {
|
|
54
62
|
year: number;
|
|
55
63
|
month: number;
|
|
56
64
|
day: number;
|
|
57
65
|
} {
|
|
58
|
-
const
|
|
59
|
-
if (!match) throw new Error(`Invalid --session value "${value}". Use YYYY-MM-DD.`);
|
|
60
|
-
const year = Number(match[1]);
|
|
61
|
-
const month = Number(match[2]);
|
|
62
|
-
const day = Number(match[3]);
|
|
63
|
-
const candidate = new Date(Date.UTC(year, month - 1, day));
|
|
64
|
-
if (
|
|
65
|
-
candidate.getUTCFullYear() !== year
|
|
66
|
-
|| candidate.getUTCMonth() !== month - 1
|
|
67
|
-
|| candidate.getUTCDate() !== day
|
|
68
|
-
) {
|
|
69
|
-
throw new Error(`Invalid --session value "${value}". Use a real calendar date.`);
|
|
70
|
-
}
|
|
66
|
+
const [year, month, day] = value.split("-").map(Number) as [number, number, number];
|
|
71
67
|
return { year, month, day };
|
|
72
68
|
}
|
|
73
69
|
|
|
@@ -152,8 +148,7 @@ export function resolveIntradaySessionWindow(
|
|
|
152
148
|
bySession.set(date, sessionPoints);
|
|
153
149
|
}
|
|
154
150
|
|
|
155
|
-
const requestedSession = options.session?.trim()
|
|
156
|
-
if (requestedSession) parseSessionDate(requestedSession);
|
|
151
|
+
const requestedSession = options.session?.trim() ? readSessionDate(options.session.trim()) : null;
|
|
157
152
|
const availableSessions = [...bySession.keys()].sort();
|
|
158
153
|
const selectedSessions = requestedSession
|
|
159
154
|
? availableSessions.filter((date) => date === requestedSession)
|
|
@@ -195,9 +190,8 @@ export function resolveIntradayRequest(options: {
|
|
|
195
190
|
support?: readonly ChartResolutionSupport[];
|
|
196
191
|
}): IntradayRequest {
|
|
197
192
|
const session = typeof options.session === "string" && options.session.trim()
|
|
198
|
-
? options.session.trim()
|
|
193
|
+
? readSessionDate(options.session.trim())
|
|
199
194
|
: null;
|
|
200
|
-
if (session) parseSessionDate(session);
|
|
201
195
|
const rangePreset = session
|
|
202
196
|
? "1D"
|
|
203
197
|
: options.rangePreset === "1W" ? "1W" : "1D";
|
|
@@ -254,13 +248,13 @@ async function loadHistoricalFallback(
|
|
|
254
248
|
if (request.session) {
|
|
255
249
|
const bounds = sessionUtcBounds(request.session, timeZone);
|
|
256
250
|
return await fetchHistoryResult(provider, symbol, exchange,
|
|
257
|
-
{ kind: "detail", start: bounds.start, end: bounds.end, interval: request.resolution }, context).catch((
|
|
251
|
+
{ kind: "detail", start: bounds.start, end: bounds.end, interval: request.resolution }, context).catch(logFailure("chart-composer.session-history", "Load requested intraday session failed", null)) ?? empty;
|
|
258
252
|
}
|
|
259
253
|
const end = new Date(now.getTime() - HISTORICAL_RETRY_DELAY_MS);
|
|
260
254
|
const lookbackDays = request.rangePreset === "1W" ? 35 : 8;
|
|
261
255
|
const start = new Date(end.getTime() - lookbackDays * DAY_MS);
|
|
262
256
|
return await fetchHistoryResult(provider, symbol, exchange,
|
|
263
|
-
{ kind: "detail", start, end, interval: request.resolution }, context).catch((
|
|
257
|
+
{ kind: "detail", start, end, interval: request.resolution }, context).catch(logFailure("chart-composer.session-history", "Load historical intraday fallback failed", null)) ?? empty;
|
|
264
258
|
}
|
|
265
259
|
|
|
266
260
|
export async function loadIntradayWindow(options: {
|
|
@@ -354,7 +348,7 @@ export async function loadIntradayWindow(options: {
|
|
|
354
348
|
if (nonpositive.length) {
|
|
355
349
|
// Metadata is needed only at this boundary. Do not infer a futures domain
|
|
356
350
|
// from a ticker suffix, a contract multiplier, or an option security type.
|
|
357
|
-
const reportedQuote = await options.provider.getQuote(options.symbol, options.exchange, options.context).catch((
|
|
351
|
+
const reportedQuote = await options.provider.getQuote(options.symbol, options.exchange, options.context).catch(logFailure("chart-composer.session-history", "Read intraday instrument metadata failed"));
|
|
358
352
|
const quote = reportedQuote?.symbol.trim().toUpperCase() === options.symbol.trim().toUpperCase()
|
|
359
353
|
? reportedQuote : undefined;
|
|
360
354
|
const instrumentType = quote?.instrumentType?.trim().toUpperCase() || null;
|