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,499 @@
|
|
|
1
|
+
import { SnapshotHistoryUnavailableError } from "../market-data/snapshot-provider";
|
|
2
|
+
import { HistoryCoverageError, historyCoverageNotice } from "../sources/history-coverage";
|
|
3
|
+
import { notATickerSymbol, ProviderMissError } from "../sources/provider-errors";
|
|
4
|
+
import { indexRootSuggestion } from "../tickers/index-roots";
|
|
5
|
+
import {
|
|
6
|
+
HISTORY_RETENTION_MAX_AGE_MS,
|
|
7
|
+
canonicalHistoryInterval,
|
|
8
|
+
isHistoryRetentionError,
|
|
9
|
+
parseHistoryRecoveryCandidate,
|
|
10
|
+
type HistoryRecoveryCandidate,
|
|
11
|
+
type HistoryRetentionError,
|
|
12
|
+
} from "../sources/history-retention";
|
|
13
|
+
import { getRouterEntityKey } from "../sources/provider-router/cache";
|
|
14
|
+
import { publicListingTarget } from "../sources/listing-target";
|
|
15
|
+
import { fetchHistoryResult } from "../sources/history-result";
|
|
16
|
+
import type { PriceHistoryResult } from "../types/price-history";
|
|
17
|
+
import { subtractTimeRange } from "./date-window";
|
|
18
|
+
import {
|
|
19
|
+
CHART_RESOLUTION_STEP_MS,
|
|
20
|
+
isIntradayResolution,
|
|
21
|
+
type ChartResolutionSupport,
|
|
22
|
+
type ManualChartResolution,
|
|
23
|
+
} from "./resolution";
|
|
24
|
+
import { TIME_RANGES, type TimeRange } from "./range";
|
|
25
|
+
import type { DataProvider, MarketDataRequestContext } from "../types/data-provider";
|
|
26
|
+
import type { TickerFinancials } from "../types/financials";
|
|
27
|
+
import { isMarketFieldId } from "./field-catalog";
|
|
28
|
+
import { isResolutionFineEnoughForMarketPeriod } from "./market-resolution";
|
|
29
|
+
import { rememberParsedPriceHistory, parsedPriceHistoryKey } from "./parsed-history-cache";
|
|
30
|
+
import { getPricePointTimestamp } from "../utils/price-history";
|
|
31
|
+
import { timeZoneLabel, zonedDateKey, zonedWallClockMs } from "../utils/zoned-date-time";
|
|
32
|
+
import { formatShortDate } from "../utils/datetime-format";
|
|
33
|
+
import { listingTimeZone } from "../market-data/market/trading-sessions";
|
|
34
|
+
import type { ChartSeriesSpec } from "./types";
|
|
35
|
+
import { type LoadedPriceHistory, requestContext, instrumentLabel } from "./resolve-context";
|
|
36
|
+
import { type DateBounds, DAY_MS, exclusiveEnd } from "./chart-bounds";
|
|
37
|
+
|
|
38
|
+
export interface PriceHistoryRequest {
|
|
39
|
+
bounds: DateBounds;
|
|
40
|
+
visibleBounds: DateBounds;
|
|
41
|
+
explicitWindow: boolean;
|
|
42
|
+
/** Dates the chart was given, not a view the user panned or zoomed to. */
|
|
43
|
+
authoredWindow: boolean;
|
|
44
|
+
fallbackRange: TimeRange;
|
|
45
|
+
resolution: ManualChartResolution;
|
|
46
|
+
allowProviderDefaultFallback: boolean;
|
|
47
|
+
support: readonly ChartResolutionSupport[];
|
|
48
|
+
requiredWarmupPoints: number;
|
|
49
|
+
historyRequestKey?: string;
|
|
50
|
+
/** Ask for pre-market and after-hours bars. */
|
|
51
|
+
historySession?: "extended";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class PriceHistoryAcquisitionError extends Error {
|
|
55
|
+
constructor(message: string, readonly retryAt: number) { super(message); }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Compatible intervals from different source/session contracts cannot share a capture. */
|
|
59
|
+
export function priceHistoryAcquisitionIdentity(result: Pick<PriceHistoryResult, "session" | "sourceKey">): string {
|
|
60
|
+
const { observedAt: _observedAt, ...session } = result.session ?? {};
|
|
61
|
+
return JSON.stringify([result.sourceKey ?? null, result.session ? session : null]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Merged history keeps the actual acquisition clock belonging to its finite tail. */
|
|
65
|
+
export function priceHistoryTailAcquisition<T extends { points: TickerFinancials["priceHistory"] }>(previous: T | undefined, incoming: T): T {
|
|
66
|
+
const latest = (value: T) => value.points.reduce((last, point) => {
|
|
67
|
+
const time = getPricePointTimestamp(point);
|
|
68
|
+
return Number.isFinite(point.close) && Number.isFinite(time) ? Math.max(last, time) : last;
|
|
69
|
+
}, Number.NEGATIVE_INFINITY);
|
|
70
|
+
return previous && latest(previous) > latest(incoming) ? previous : incoming;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Shown while a current chart draws a saved copy that no refetch brought up
|
|
75
|
+
* to date: the last saved bar on the venue's clock, as the axis reads it.
|
|
76
|
+
*/
|
|
77
|
+
export function behindHistoryNotice(
|
|
78
|
+
source: Extract<ChartSeriesSpec["source"], { kind: "security" }>,
|
|
79
|
+
points: TickerFinancials["priceHistory"],
|
|
80
|
+
now: number,
|
|
81
|
+
): string | null {
|
|
82
|
+
const latest = points.findLast((point) => Number.isFinite(point.close) && Number.isFinite(getPricePointTimestamp(point)));
|
|
83
|
+
if (!latest) return null;
|
|
84
|
+
const zone = listingTimeZone(source.instrument.symbol, source.instrument.exchange) ?? "UTC";
|
|
85
|
+
const wall = new Date(zonedWallClockMs(getPricePointTimestamp(latest), zone)).toISOString();
|
|
86
|
+
const sameYear = wall.slice(0, 4) === zonedDateKey(now, zone).slice(0, 4);
|
|
87
|
+
const day = formatShortDate(wall.slice(0, 10), { utc: true, year: sameYear ? false : "numeric" });
|
|
88
|
+
return `${instrumentLabel(source)}: newer bars are unavailable; showing saved bars as of ${day} ${wall.slice(11, 16)} ${timeZoneLabel(zone)}.`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function isSortedPriceHistory(points: TickerFinancials["priceHistory"]): boolean {
|
|
92
|
+
let previous = Number.NEGATIVE_INFINITY;
|
|
93
|
+
for (const point of points) {
|
|
94
|
+
const timestamp = getPricePointTimestamp(point);
|
|
95
|
+
if (!Number.isFinite(timestamp)) continue;
|
|
96
|
+
if (timestamp < previous) return false;
|
|
97
|
+
previous = timestamp;
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Two closes of one session further apart than this are on different split bases, not a revision. */
|
|
103
|
+
const SAME_BASIS_LIMIT = Math.log(1.4);
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Whether two windows of one history are on the same split basis: most of the
|
|
107
|
+
* sessions both hold close within 40% of each other. A window acquired before
|
|
108
|
+
* a split and one acquired after it hold the same sessions about the split's
|
|
109
|
+
* ratio apart (NRDY's 18 Aug 2026 close, 0.654 before its 1-for-15 reverse
|
|
110
|
+
* split and 9.81 after it), and merged they would draw that ratio as a move.
|
|
111
|
+
* Windows that share no session cannot be told apart and agree.
|
|
112
|
+
*/
|
|
113
|
+
export function priceHistoryWindowsAgree(
|
|
114
|
+
current: TickerFinancials["priceHistory"],
|
|
115
|
+
incoming: TickerFinancials["priceHistory"],
|
|
116
|
+
resolution: ManualChartResolution,
|
|
117
|
+
): boolean {
|
|
118
|
+
if (current.length === 0 || incoming.length === 0) return true;
|
|
119
|
+
// Daily and slower bars stamped differently by two sources are one session within this.
|
|
120
|
+
const tolerance = isIntradayResolution(resolution) ? 0 : CHART_RESOLUTION_STEP_MS[resolution] * 0.8;
|
|
121
|
+
const closes = current
|
|
122
|
+
.map((point) => ({ time: getPricePointTimestamp(point), close: point.close }))
|
|
123
|
+
.filter((point) => Number.isFinite(point.time) && Number.isFinite(point.close) && point.close > 0)
|
|
124
|
+
.sort((left, right) => left.time - right.time);
|
|
125
|
+
let same = 0;
|
|
126
|
+
let other = 0;
|
|
127
|
+
for (const point of incoming) {
|
|
128
|
+
const time = getPricePointTimestamp(point);
|
|
129
|
+
if (!Number.isFinite(time) || !Number.isFinite(point.close) || !(point.close > 0)) continue;
|
|
130
|
+
let low = 0;
|
|
131
|
+
let high = closes.length;
|
|
132
|
+
while (low < high) {
|
|
133
|
+
const middle = (low + high) >> 1;
|
|
134
|
+
if (closes[middle]!.time < time) low = middle + 1;
|
|
135
|
+
else high = middle;
|
|
136
|
+
}
|
|
137
|
+
const nearest = [closes[low - 1], closes[low]]
|
|
138
|
+
.filter((candidate) => candidate && Math.abs(candidate.time - time) <= tolerance)
|
|
139
|
+
.sort((left, right) => Math.abs(left!.time - time) - Math.abs(right!.time - time))[0];
|
|
140
|
+
if (!nearest) continue;
|
|
141
|
+
if (Math.abs(Math.log(point.close / nearest.close)) > SAME_BASIS_LIMIT) other += 1;
|
|
142
|
+
else same += 1;
|
|
143
|
+
}
|
|
144
|
+
return other <= same;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function mergePriceHistoryWindows(
|
|
148
|
+
current: TickerFinancials["priceHistory"],
|
|
149
|
+
incoming: TickerFinancials["priceHistory"],
|
|
150
|
+
resolution: ManualChartResolution,
|
|
151
|
+
): TickerFinancials["priceHistory"] {
|
|
152
|
+
// A window on another split basis than the incoming one is dropped, never merged into it.
|
|
153
|
+
if (!priceHistoryWindowsAgree(current, incoming, resolution)) current = [];
|
|
154
|
+
let sorted: TickerFinancials["priceHistory"];
|
|
155
|
+
if (!isSortedPriceHistory(current) || !isSortedPriceHistory(incoming)) {
|
|
156
|
+
const byTimestamp = new Map<number, TickerFinancials["priceHistory"][number]>();
|
|
157
|
+
for (const point of [...current, ...incoming]) {
|
|
158
|
+
const timestamp = getPricePointTimestamp(point);
|
|
159
|
+
if (Number.isFinite(timestamp)) {
|
|
160
|
+
byTimestamp.set(
|
|
161
|
+
timestamp,
|
|
162
|
+
point.date instanceof Date ? point : { ...point, date: new Date(timestamp) },
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
sorted = [...byTimestamp.values()].sort(
|
|
167
|
+
(left, right) => getPricePointTimestamp(left) - getPricePointTimestamp(right),
|
|
168
|
+
);
|
|
169
|
+
} else {
|
|
170
|
+
sorted = [];
|
|
171
|
+
let currentIndex = 0;
|
|
172
|
+
let incomingIndex = 0;
|
|
173
|
+
// An intraday point strictly inside a later window's bar is that window's
|
|
174
|
+
// earlier observation of it, such as a trade-time final print.
|
|
175
|
+
const step = isIntradayResolution(resolution) ? CHART_RESOLUTION_STEP_MS[resolution] : 0;
|
|
176
|
+
let coveredUntil = Number.NEGATIVE_INFINITY;
|
|
177
|
+
const append = (
|
|
178
|
+
point: TickerFinancials["priceHistory"][number],
|
|
179
|
+
timestamp: number,
|
|
180
|
+
) => {
|
|
181
|
+
const normalized = point.date instanceof Date ? point : { ...point, date: new Date(timestamp) };
|
|
182
|
+
const previous = sorted.at(-1);
|
|
183
|
+
if (previous && getPricePointTimestamp(previous) === timestamp) sorted[sorted.length - 1] = normalized;
|
|
184
|
+
else sorted.push(normalized);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
while (currentIndex < current.length || incomingIndex < incoming.length) {
|
|
188
|
+
const currentPoint = current[currentIndex];
|
|
189
|
+
const incomingPoint = incoming[incomingIndex];
|
|
190
|
+
const currentTimestamp = currentPoint ? getPricePointTimestamp(currentPoint) : Number.POSITIVE_INFINITY;
|
|
191
|
+
const incomingTimestamp = incomingPoint ? getPricePointTimestamp(incomingPoint) : Number.POSITIVE_INFINITY;
|
|
192
|
+
if (currentPoint && !Number.isFinite(currentTimestamp)) {
|
|
193
|
+
currentIndex += 1;
|
|
194
|
+
} else if (incomingPoint && !Number.isFinite(incomingTimestamp)) {
|
|
195
|
+
incomingIndex += 1;
|
|
196
|
+
} else if (currentPoint && currentTimestamp <= incomingTimestamp) {
|
|
197
|
+
if (!(incomingPoint && currentTimestamp < incomingTimestamp && currentTimestamp < coveredUntil)) {
|
|
198
|
+
append(currentPoint, currentTimestamp);
|
|
199
|
+
}
|
|
200
|
+
currentIndex += 1;
|
|
201
|
+
} else if (incomingPoint) {
|
|
202
|
+
append(incomingPoint, incomingTimestamp);
|
|
203
|
+
if (step) coveredUntil = incomingTimestamp + step;
|
|
204
|
+
incomingIndex += 1;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (isIntradayResolution(resolution)) return sorted;
|
|
210
|
+
// Windows can be served by different sources, and they stamp the same session
|
|
211
|
+
// differently: local midnight, UTC midnight, or the opening bell. Keying on the
|
|
212
|
+
// exact timestamp keeps both copies, so the chart draws every bar twice and
|
|
213
|
+
// carries twice the points through every pan. Daily and slower bars are never
|
|
214
|
+
// closer than one step apart, so anything closer is the same session; keep the
|
|
215
|
+
// copy already plotted to leave existing bars where they are.
|
|
216
|
+
const minimumGapMs = CHART_RESOLUTION_STEP_MS[resolution] * 0.8;
|
|
217
|
+
const plotted = new Set(current.map(getPricePointTimestamp));
|
|
218
|
+
const merged: TickerFinancials["priceHistory"] = [];
|
|
219
|
+
for (const point of sorted) {
|
|
220
|
+
const previous = merged.at(-1);
|
|
221
|
+
if (!previous || getPricePointTimestamp(point) - getPricePointTimestamp(previous) >= minimumGapMs) {
|
|
222
|
+
merged.push(point);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (!plotted.has(getPricePointTimestamp(previous)) && plotted.has(getPricePointTimestamp(point))) {
|
|
226
|
+
merged[merged.length - 1] = point;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return merged;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function historyIntersectsBounds(
|
|
233
|
+
history: TickerFinancials["priceHistory"],
|
|
234
|
+
bounds: DateBounds,
|
|
235
|
+
): boolean {
|
|
236
|
+
if (history.length === 0) return false;
|
|
237
|
+
if (bounds.start === null || bounds.end === null) return true;
|
|
238
|
+
return history.some((point) => {
|
|
239
|
+
const timestamp = getPricePointTimestamp(point);
|
|
240
|
+
return Number.isFinite(timestamp) && timestamp >= bounds.start! && timestamp <= bounds.end!;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function clampHistoryBoundsToSupport(
|
|
245
|
+
bounds: DateBounds,
|
|
246
|
+
maxRange: TimeRange | null,
|
|
247
|
+
durationEnd: number | null = bounds.end,
|
|
248
|
+
): DateBounds {
|
|
249
|
+
if (bounds.start === null || bounds.end === null || !maxRange || maxRange === "ALL") {
|
|
250
|
+
return bounds;
|
|
251
|
+
}
|
|
252
|
+
const supportedStart = subtractTimeRange(new Date(durationEnd ?? bounds.end), maxRange).getTime();
|
|
253
|
+
return { start: Math.max(bounds.start, supportedStart), end: bounds.end };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function retainedWarmup(points: TickerFinancials["priceHistory"], visibleStart: number | null): number {
|
|
257
|
+
return visibleStart === null ? 0 : points.filter((point) => Number.isFinite(point.close)
|
|
258
|
+
&& getPricePointTimestamp(point) < visibleStart).length;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function recoveryCandidates(
|
|
262
|
+
error: HistoryRetentionError,
|
|
263
|
+
provider: DataProvider,
|
|
264
|
+
source: Extract<ChartSeriesSpec["source"], { kind: "security" }>,
|
|
265
|
+
): readonly HistoryRecoveryCandidate[] {
|
|
266
|
+
if (error.candidates.length) return error.candidates;
|
|
267
|
+
// A direct Cloud adapter enforces this constraint itself. Routed errors must
|
|
268
|
+
// carry the router's actual attempted-source scope, including across RPC.
|
|
269
|
+
if (provider.id !== "gloomberb-cloud") return [];
|
|
270
|
+
const target = publicListingTarget(source.instrument.symbol, source.instrument.exchange);
|
|
271
|
+
const context = requestContext(source);
|
|
272
|
+
const candidate = parseHistoryRecoveryCandidate({
|
|
273
|
+
sourceKey: `provider:${provider.id}`, retention: error.retention,
|
|
274
|
+
request: { symbol: target.symbol, exchange: target.exchange ?? "",
|
|
275
|
+
entityKey: getRouterEntityKey(source.instrument.symbol, context.instrument),
|
|
276
|
+
brokerId: context.brokerId, brokerInstanceId: context.brokerInstanceId,
|
|
277
|
+
interval: error.retention.interval, requestedStart: error.retention.requestedStart,
|
|
278
|
+
requestedEnd: error.retention.requestedEnd },
|
|
279
|
+
});
|
|
280
|
+
return candidate ? [candidate] : [];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Requests for older bars one panned window may add when its source answers only the newest part. */
|
|
284
|
+
const OLDER_BAR_REQUESTS = 3;
|
|
285
|
+
/** A window may start this far before its first bar for closed sessions alone: weekends and holiday weeks. */
|
|
286
|
+
const CLOSED_SESSION_GAP_MS = 10 * DAY_MS;
|
|
287
|
+
/**
|
|
288
|
+
* An answer cut short at the source's cap holds thousands of bars. A shorter
|
|
289
|
+
* one that starts late is a young listing or a source that keeps less: it
|
|
290
|
+
* holds all there is, and an older request cannot change that.
|
|
291
|
+
*/
|
|
292
|
+
const CAPPED_ANSWER_MIN_BARS = 1_000;
|
|
293
|
+
|
|
294
|
+
function firstBarTime(points: TickerFinancials["priceHistory"]): number {
|
|
295
|
+
for (const point of points) {
|
|
296
|
+
const time = getPricePointTimestamp(point);
|
|
297
|
+
if (Number.isFinite(time) && Number.isFinite(point.close)) return time;
|
|
298
|
+
}
|
|
299
|
+
return Number.NaN;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* A source caps the bars one request returns and answers with the newest, so
|
|
304
|
+
* a panned window can come back starting weeks after it was asked to. The
|
|
305
|
+
* older part is asked for on its own, from the same source and session, until
|
|
306
|
+
* it is covered or the source has nothing older: then the first bar is where
|
|
307
|
+
* this listing's history at this cadence starts, and the chart stops there
|
|
308
|
+
* instead of asking again. So does an answer that starts late without being
|
|
309
|
+
* cut short, or one the source says its coverage starts with.
|
|
310
|
+
*/
|
|
311
|
+
async function withOlderBars(
|
|
312
|
+
provider: DataProvider,
|
|
313
|
+
source: Extract<ChartSeriesSpec["source"], { kind: "security" }>,
|
|
314
|
+
request: PriceHistoryRequest,
|
|
315
|
+
result: PriceHistoryResult,
|
|
316
|
+
context: MarketDataRequestContext,
|
|
317
|
+
): Promise<LoadedPriceHistory> {
|
|
318
|
+
const start = request.bounds.start;
|
|
319
|
+
const end = request.bounds.end;
|
|
320
|
+
if (start === null || end === null || result.resolution !== request.resolution) return result;
|
|
321
|
+
const toleranceMs = Math.max(CLOSED_SESSION_GAP_MS, (end - start) / 5);
|
|
322
|
+
let current: LoadedPriceHistory = result;
|
|
323
|
+
let answerBars = result.points.length;
|
|
324
|
+
for (let attempt = 0; attempt < OLDER_BAR_REQUESTS; attempt += 1) {
|
|
325
|
+
const first = firstBarTime(current.points);
|
|
326
|
+
if (!Number.isFinite(first) || first - start <= toleranceMs) return current;
|
|
327
|
+
// An answer short of the cap that still starts late is everything the source has.
|
|
328
|
+
if (answerBars < CAPPED_ANSWER_MIN_BARS || current.coverageStart) return { ...current, historyStart: first };
|
|
329
|
+
let older: PriceHistoryResult | null;
|
|
330
|
+
try {
|
|
331
|
+
older = await fetchHistoryResult(provider, source.instrument.symbol, source.instrument.exchange ?? "",
|
|
332
|
+
{ kind: "detail", start: new Date(start), end: new Date(first), interval: request.resolution }, context);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
// The source keeps nothing that old, by its own account; anything else may pass.
|
|
335
|
+
return isHistoryRetentionError(error) || error instanceof ProviderMissError
|
|
336
|
+
? { ...current, historyStart: first } : current;
|
|
337
|
+
}
|
|
338
|
+
if (!older || older.resolution !== current.resolution
|
|
339
|
+
|| priceHistoryAcquisitionIdentity(older) !== priceHistoryAcquisitionIdentity(current)) return current;
|
|
340
|
+
const earlier = older.points.filter((point) => getPricePointTimestamp(point) < first);
|
|
341
|
+
if (!Number.isFinite(firstBarTime(earlier))) return { ...current, historyStart: first };
|
|
342
|
+
current = { ...current, points: [...earlier, ...current.points] };
|
|
343
|
+
answerBars = older.points.length;
|
|
344
|
+
}
|
|
345
|
+
return current;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* A failure that says no listing carries the symbol, offering the index a
|
|
350
|
+
* bare root names: `Not a ticker: VIX. Did you mean ^VIX (Cboe Volatility
|
|
351
|
+
* Index)?`. Null for any other failure.
|
|
352
|
+
*/
|
|
353
|
+
function notATickerText(error: unknown): string | null {
|
|
354
|
+
const message = error instanceof Error ? error.message.split("\n")[0]! : "";
|
|
355
|
+
const symbol = notATickerSymbol(message);
|
|
356
|
+
if (!symbol) return null;
|
|
357
|
+
const suggestion = message.includes(" Did you mean ") ? null : indexRootSuggestion(symbol);
|
|
358
|
+
return suggestion ? `Not a ticker: ${symbol}. ${suggestion}` : message;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export async function loadPriceHistory(
|
|
362
|
+
provider: DataProvider,
|
|
363
|
+
source: Extract<ChartSeriesSpec["source"], { kind: "security" }>,
|
|
364
|
+
request: PriceHistoryRequest,
|
|
365
|
+
): Promise<LoadedPriceHistory> {
|
|
366
|
+
const context = { ...requestContext(source), historyRequestKey: request.historyRequestKey,
|
|
367
|
+
...(request.historySession ? { historySession: request.historySession } : {}) };
|
|
368
|
+
let coverageNotice: string | null = null;
|
|
369
|
+
let retentionError: HistoryRetentionError | null = null;
|
|
370
|
+
// No source has a listing for the symbol: no bar size would help, so the failure says that instead.
|
|
371
|
+
let notATicker: string | null = null;
|
|
372
|
+
const observeFailure = (error: unknown) => {
|
|
373
|
+
if (error instanceof SnapshotHistoryUnavailableError) throw error;
|
|
374
|
+
if (error instanceof HistoryCoverageError) coverageNotice ??= error.message;
|
|
375
|
+
if (isHistoryRetentionError(error)) retentionError ??= error;
|
|
376
|
+
notATicker ??= notATickerText(error);
|
|
377
|
+
};
|
|
378
|
+
const observeCoverage = (result: PriceHistoryResult) => {
|
|
379
|
+
coverageNotice ??= historyCoverageNotice(result.coverageStart, request.visibleBounds.start);
|
|
380
|
+
};
|
|
381
|
+
const accepted = (points: TickerFinancials["priceHistory"]) => points.length > 0
|
|
382
|
+
&& (!request.explicitWindow || historyIntersectsBounds(points, request.visibleBounds));
|
|
383
|
+
const detailStart = request.bounds.start === null ? null : new Date(request.bounds.start);
|
|
384
|
+
const detailEnd = exclusiveEnd(request.bounds);
|
|
385
|
+
if (request.explicitWindow && detailStart && detailEnd && (provider.getDetailedPriceHistoryWithMetadata || provider.getDetailedPriceHistory)) {
|
|
386
|
+
try {
|
|
387
|
+
const result = (await fetchHistoryResult(provider, source.instrument.symbol, source.instrument.exchange ?? "",
|
|
388
|
+
{ kind: "detail", start: detailStart, end: detailEnd, interval: request.resolution }, context))!;
|
|
389
|
+
const { points } = result;
|
|
390
|
+
observeCoverage(result);
|
|
391
|
+
// Authored dates chart what their source answers; a panned view reaches for the rest.
|
|
392
|
+
if (accepted(points)) return request.authoredWindow ? result : await withOlderBars(provider, source, request, result, context);
|
|
393
|
+
} catch (error) { observeFailure(error); }
|
|
394
|
+
}
|
|
395
|
+
if (provider.getPriceHistoryForResolutionWithMetadata || provider.getPriceHistoryForResolution) {
|
|
396
|
+
try {
|
|
397
|
+
const result = (await fetchHistoryResult(provider, source.instrument.symbol, source.instrument.exchange ?? "",
|
|
398
|
+
{ kind: "resolution", range: request.fallbackRange, resolution: request.resolution }, context))!;
|
|
399
|
+
const { points } = result;
|
|
400
|
+
observeCoverage(result);
|
|
401
|
+
if (accepted(points)) {
|
|
402
|
+
rememberParsedPriceHistory(parsedPriceHistoryKey(source.instrument, request.fallbackRange, request.resolution), points, result);
|
|
403
|
+
return result;
|
|
404
|
+
}
|
|
405
|
+
} catch (error) { observeFailure(error); }
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Only original source/cache exhaustion reaches recovery. Ask the selected
|
|
409
|
+
// source for its retained window; a nominal clock multiplier cannot guarantee
|
|
410
|
+
// enough observations across exchange closures for a study's warmup.
|
|
411
|
+
const retainedFailure = retentionError as HistoryRetentionError | null;
|
|
412
|
+
let recoveryAttempted = false;
|
|
413
|
+
const retryAt = retainedFailure ? retainedFailure.retention.observedAt + HISTORY_RETENTION_MAX_AGE_MS : undefined;
|
|
414
|
+
if (retainedFailure && !coverageNotice && (provider.getDetailedPriceHistoryWithMetadata || provider.getDetailedPriceHistory)) {
|
|
415
|
+
const step = CHART_RESOLUTION_STEP_MS[request.resolution];
|
|
416
|
+
const target = publicListingTarget(source.instrument.symbol, source.instrument.exchange);
|
|
417
|
+
const candidate = recoveryCandidates(retainedFailure, provider, source).map((value) => parseHistoryRecoveryCandidate(value))
|
|
418
|
+
.find((value) => value && value.request.symbol === target.symbol
|
|
419
|
+
&& value.request.exchange === (target.exchange ?? "")
|
|
420
|
+
&& value.request.interval === canonicalHistoryInterval(request.resolution)
|
|
421
|
+
&& value.request.entityKey === getRouterEntityKey(source.instrument.symbol, context.instrument)
|
|
422
|
+
&& value.request.brokerId === context.brokerId && value.request.brokerInstanceId === context.brokerInstanceId);
|
|
423
|
+
if (candidate && request.visibleBounds.start !== null) {
|
|
424
|
+
// One complete bar inside the advancing source limit absorbs acquisition
|
|
425
|
+
// latency. Keep the source's original exclusive end at its second precision.
|
|
426
|
+
const start = Math.ceil(candidate.retention.availableStart / step) * step + step;
|
|
427
|
+
const end = candidate.retention.requestedEnd;
|
|
428
|
+
const visibleEnd = request.visibleBounds.end === null ? end : Math.floor(request.visibleBounds.end / 1000) * 1000;
|
|
429
|
+
// At an interval the user chose, a preset range or a panned or zoomed
|
|
430
|
+
// view that reaches back past the retained bars, but still reaches them,
|
|
431
|
+
// charts what the source keeps. Auto steps to coarser bars below instead,
|
|
432
|
+
// and authored dates keep failing.
|
|
433
|
+
const retainedOnly = !request.allowProviderDefaultFallback && !request.authoredWindow && visibleEnd >= start;
|
|
434
|
+
if ((retainedOnly || request.visibleBounds.start >= start) && visibleEnd <= end && start < end) {
|
|
435
|
+
recoveryAttempted = true;
|
|
436
|
+
try {
|
|
437
|
+
const result = (await fetchHistoryResult(provider, source.instrument.symbol, source.instrument.exchange ?? "",
|
|
438
|
+
{ kind: "detail", start: new Date(start), end: new Date(end), interval: request.resolution }, { ...context, historyRecovery: candidate }))!;
|
|
439
|
+
const { points } = result;
|
|
440
|
+
observeCoverage(result);
|
|
441
|
+
if (accepted(points)) return { ...result, expiresAt: retryAt, historyStart: firstBarTime(points),
|
|
442
|
+
recovery: { sourceKey: candidate.sourceKey, start, end, requiredWarmupPoints: request.requiredWarmupPoints,
|
|
443
|
+
usableWarmupPoints: retainedWarmup(points, request.visibleBounds.start), retention: candidate.retention } };
|
|
444
|
+
} catch (error) { observeFailure(error); }
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const unavailable = () => coverageNotice ?? notATicker
|
|
450
|
+
?? `Requested ${request.resolution} price history is unavailable for ${instrumentLabel(source)}.`;
|
|
451
|
+
const fail = (message: string): never => {
|
|
452
|
+
if (retryAt !== undefined) throw new PriceHistoryAcquisitionError(message, retryAt);
|
|
453
|
+
throw new Error(message);
|
|
454
|
+
};
|
|
455
|
+
if (!request.allowProviderDefaultFallback || recoveryAttempted) return fail(unavailable());
|
|
456
|
+
|
|
457
|
+
// After a proved retention failure, one explicit calendar fallback can retain
|
|
458
|
+
// the familiar broader chart with known cadence. Never substitute coarser bars
|
|
459
|
+
// for an authored financial/market period that requires finer observations.
|
|
460
|
+
const coarser = retainedFailure && (provider.getPriceHistoryForResolutionWithMetadata || provider.getPriceHistoryForResolution)
|
|
461
|
+
? (["1d", "1wk", "1mo"] as const).find((resolution) =>
|
|
462
|
+
CHART_RESOLUTION_STEP_MS[resolution] > CHART_RESOLUTION_STEP_MS[request.resolution]
|
|
463
|
+
&& isResolutionFineEnoughForMarketPeriod(resolution, source.period)
|
|
464
|
+
&& request.support.some((entry) => entry.resolution === resolution
|
|
465
|
+
&& TIME_RANGES.indexOf(entry.maxRange) >= TIME_RANGES.indexOf(request.fallbackRange))) : undefined;
|
|
466
|
+
if (coarser) {
|
|
467
|
+
try {
|
|
468
|
+
const result = (await fetchHistoryResult(provider, source.instrument.symbol, source.instrument.exchange ?? "",
|
|
469
|
+
{ kind: "resolution", range: request.fallbackRange, resolution: coarser }, context))!;
|
|
470
|
+
const { points } = result;
|
|
471
|
+
observeCoverage(result);
|
|
472
|
+
if (accepted(points)) {
|
|
473
|
+
rememberParsedPriceHistory(parsedPriceHistoryKey(source.instrument, request.fallbackRange, coarser), points, result);
|
|
474
|
+
return { ...result, expiresAt: retryAt };
|
|
475
|
+
}
|
|
476
|
+
} catch (error) { observeFailure(error); }
|
|
477
|
+
return fail(unavailable());
|
|
478
|
+
}
|
|
479
|
+
if (retainedFailure) return fail(unavailable());
|
|
480
|
+
if (!provider.getPriceHistoryWithMetadata && source.period && source.period !== "auto" && isMarketFieldId(source.fieldId)) return fail(unavailable());
|
|
481
|
+
let result: PriceHistoryResult;
|
|
482
|
+
try {
|
|
483
|
+
result = (await fetchHistoryResult(provider, source.instrument.symbol, source.instrument.exchange ?? "",
|
|
484
|
+
{ kind: "range", range: request.fallbackRange }, context))!;
|
|
485
|
+
if (source.period && source.period !== "auto" && isMarketFieldId(source.fieldId)
|
|
486
|
+
&& (result.resolution === null || !isResolutionFineEnoughForMarketPeriod(result.resolution, source.period))) return fail(unavailable());
|
|
487
|
+
} catch (error) {
|
|
488
|
+
return fail(coverageNotice ?? notATickerText(error) ?? (error instanceof Error ? error.message : String(error)));
|
|
489
|
+
}
|
|
490
|
+
const { points } = result;
|
|
491
|
+
observeCoverage(result);
|
|
492
|
+
if (points.length === 0 && coverageNotice) return fail(coverageNotice);
|
|
493
|
+
if (request.explicitWindow && points.length > 0 && !historyIntersectsBounds(points, request.visibleBounds)) {
|
|
494
|
+
return fail(coverageNotice ?? `Price history for the requested window is unavailable for ${instrumentLabel(source)}.`);
|
|
495
|
+
}
|
|
496
|
+
// A default-only provider remains usable, but its bare array cannot establish
|
|
497
|
+
// an interval for live-bar merging, annualization or a requested-cadence cache.
|
|
498
|
+
return { ...result, expiresAt: retryAt ?? Date.now() + HISTORY_RETENTION_MAX_AGE_MS };
|
|
499
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { scalarPointValue } from "./alignment";
|
|
2
|
+
import { observationDate } from "./price-comparison";
|
|
3
|
+
import type { ResolvedSeries, TimeSeriesPoint } from "./types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Where a study measures from and to, per input series: the session a price
|
|
7
|
+
* comparison starts its legs at and the one it ends them at. Null ends take
|
|
8
|
+
* the series' own first or last observation.
|
|
9
|
+
*/
|
|
10
|
+
export interface StudyAnchor {
|
|
11
|
+
start: number | null;
|
|
12
|
+
end: number | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** A daily objective a fund can have: 3 (TQQQ), -3 (SQQQ), 1.5 (UVXY), -0.5. */
|
|
16
|
+
export function isLeverageFactor(value: unknown): value is number {
|
|
17
|
+
return typeof value === "number" && Number.isFinite(value) && value !== 0 && Math.abs(value) <= 5;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** `3×`, `-3×`, `1.5×`: a factor as sponsors write it, without float noise. */
|
|
21
|
+
export function leverageFactorLabel(factor: number): string {
|
|
22
|
+
return `${Number(factor.toFixed(4))}×`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** What a series is of, for a label: its listing's symbol (`QQQ`), else its label. */
|
|
26
|
+
export function leverageSymbol(series: Pick<ResolvedSeries, "listing" | "label">): string {
|
|
27
|
+
return series.listing?.symbol ?? series.label;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface SessionClose {
|
|
31
|
+
day: string;
|
|
32
|
+
point: TimeSeriesPoint;
|
|
33
|
+
close: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** A series' closes from its anchor to its end, one per session, oldest first. */
|
|
37
|
+
export function sessionCloses(series: ResolvedSeries, anchor: StudyAnchor | undefined): SessionClose[] {
|
|
38
|
+
const closes = new Map<string, SessionClose>();
|
|
39
|
+
for (const point of series.points) {
|
|
40
|
+
const time = point.date.getTime();
|
|
41
|
+
const close = scalarPointValue(point);
|
|
42
|
+
if (close === null || !Number.isFinite(close) || close <= 0) continue;
|
|
43
|
+
if (anchor?.start != null && time < anchor.start) continue;
|
|
44
|
+
if (anchor?.end != null && time > anchor.end) continue;
|
|
45
|
+
closes.set(observationDate(time, series), { day: observationDate(time, series), point, close });
|
|
46
|
+
}
|
|
47
|
+
return [...closes.values()].sort((left, right) => left.day.localeCompare(right.day));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The line a daily objective draws, as growth of 1 from the first close:
|
|
52
|
+
* each session `factor` times the index fund's return that session,
|
|
53
|
+
* compounded. TQQQ seeks 3× QQQ's return each day, not over a month.
|
|
54
|
+
*/
|
|
55
|
+
export function dailyLeverageGrowth(closes: readonly number[], factor: number): number[] {
|
|
56
|
+
const growth: number[] = [];
|
|
57
|
+
for (let index = 0; index < closes.length; index += 1) {
|
|
58
|
+
growth.push(index === 0 ? 1 : growth[index - 1]! * (1 + factor * (closes[index]! / closes[index - 1]! - 1)));
|
|
59
|
+
}
|
|
60
|
+
return growth;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Each session's figures, as returns from the first in percent. */
|
|
64
|
+
export interface LeverageDecayPoint {
|
|
65
|
+
day: string;
|
|
66
|
+
point: TimeSeriesPoint;
|
|
67
|
+
/** The fund's own return. */
|
|
68
|
+
fund: number;
|
|
69
|
+
/** The `factor`× daily line's return. */
|
|
70
|
+
daily: number;
|
|
71
|
+
/** `factor` times the index fund's return over the period. */
|
|
72
|
+
period: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A leveraged fund against its objective, session by session from the first
|
|
77
|
+
* both have a close on: its return, the `factor`× daily line's, and `factor`
|
|
78
|
+
* times the index fund's return over the period. The line compounds over
|
|
79
|
+
* every session the index fund has; the figures are read on the sessions the
|
|
80
|
+
* fund has too.
|
|
81
|
+
*/
|
|
82
|
+
export function leverageDecayPoints(fund: readonly SessionClose[], index: readonly SessionClose[], factor: number): LeverageDecayPoint[] {
|
|
83
|
+
const fundByDay = new Map(fund.map((entry) => [entry.day, entry]));
|
|
84
|
+
const start = index.findIndex((entry) => fundByDay.has(entry.day));
|
|
85
|
+
if (start < 0) return [];
|
|
86
|
+
const legs = index.slice(start);
|
|
87
|
+
const growth = dailyLeverageGrowth(legs.map((entry) => entry.close), factor);
|
|
88
|
+
const fundStart = fundByDay.get(legs[0]!.day)!.close;
|
|
89
|
+
const indexStart = legs[0]!.close;
|
|
90
|
+
return legs.flatMap((entry, position) => {
|
|
91
|
+
const own = fundByDay.get(entry.day);
|
|
92
|
+
return own ? [{
|
|
93
|
+
day: entry.day,
|
|
94
|
+
point: own.point,
|
|
95
|
+
fund: (own.close / fundStart - 1) * 100,
|
|
96
|
+
daily: (growth[position]! - 1) * 100,
|
|
97
|
+
period: factor * (entry.close / indexStart - 1) * 100,
|
|
98
|
+
}] : [];
|
|
99
|
+
});
|
|
100
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CHART_RESOLUTION_STEP_MS,
|
|
3
|
+
chartBarSizeStepMs,
|
|
4
|
+
type ChartBarSize,
|
|
3
5
|
type ManualChartResolution,
|
|
4
6
|
} from "./resolution";
|
|
5
7
|
import { isMarketFieldId } from "./field-catalog";
|
|
@@ -18,12 +20,12 @@ export function maximumResolutionForMarketPeriod(
|
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export function isResolutionFineEnoughForMarketPeriod(
|
|
21
|
-
resolution:
|
|
23
|
+
resolution: ChartBarSize,
|
|
22
24
|
period: SeriesPeriod | undefined,
|
|
23
25
|
): boolean {
|
|
24
26
|
const maximum = maximumResolutionForMarketPeriod(period);
|
|
25
27
|
return maximum === null
|
|
26
|
-
||
|
|
28
|
+
|| chartBarSizeStepMs(resolution) <= CHART_RESOLUTION_STEP_MS[maximum];
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
/** Returns the finest fetch cadence required by explicit market periods. */
|
|
@@ -58,7 +58,8 @@ function aggregatePriceHistory(
|
|
|
58
58
|
const sorted = points
|
|
59
59
|
.flatMap((point) => {
|
|
60
60
|
const date = pricePointDate(point.date);
|
|
61
|
-
|
|
61
|
+
// A bar built from shorter ones carries the integrity of any of them that contradict themselves.
|
|
62
|
+
const integrity = (point as { integrity?: PriceHistoryIntegrity }).integrity ?? pricePointIntegrity(point);
|
|
62
63
|
return date ? [{ ...point, date, integrity }] : [];
|
|
63
64
|
})
|
|
64
65
|
.sort((left, right) => left.date.getTime() - right.date.getTime());
|