gloomberb 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -1
- package/src/api-client/auth.ts +1 -0
- package/src/api-client/index.test.ts +359 -108
- package/src/api-client/index.ts +24 -13
- package/src/api-client/socket.ts +70 -35
- package/src/api-client/types.ts +1 -1
- package/src/app/language-observer.test.tsx +82 -0
- package/src/app/language-observer.tsx +13 -0
- package/src/app/pane-runtime/index.tsx +2 -2
- package/src/app/pane-runtime/pane-settings-runtime.tsx +2 -2
- package/src/app/pane-runtime/pane-template-runtime.ts +2 -2
- package/src/app/pane-runtime/plugin-bindings.ts +2 -2
- package/src/app/pane-runtime/ticker-open-runtime.ts +2 -2
- package/src/app/runtime/broker-import.ts +2 -2
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +2 -2
- package/src/app.tsx +16 -7
- package/src/brokers/account-cache.ts +6 -6
- package/src/brokers/broker-ticker-sync.ts +3 -3
- package/src/brokers/remote-broker-adapter.ts +2 -2
- package/src/brokers/sync-broker-instance.ts +5 -6
- package/src/cli/commands/api.ts +3 -6
- package/src/cli/commands/automation.ts +7 -15
- package/src/cli/commands/market.ts +26 -61
- package/src/cli/commands/overview.ts +34 -45
- package/src/cli/commands/search.ts +25 -27
- package/src/cli/commands/system.ts +27 -57
- package/src/cli/commands/ticker.ts +62 -63
- package/src/cli/context.test.ts +63 -0
- package/src/cli/context.ts +15 -1
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/data.ts +2 -19
- package/src/cli/pane-functions/index.ts +26 -25
- package/src/cli/pane-functions/report.ts +1 -1
- package/src/cli/pane-functions/screenshot.ts +3 -3
- package/src/cli/scoped-context.ts +41 -0
- package/src/components/chart/composite/composite-chart.test.tsx +615 -18
- package/src/components/chart/composite/composite-chart.tsx +179 -79
- package/src/components/chart/composite/format.test.ts +20 -7
- package/src/components/chart/composite/index.ts +0 -21
- package/src/components/chart/composite/interactions.test.ts +90 -3
- package/src/components/chart/composite/interactions.ts +189 -24
- package/src/components/chart/composite/price-series.ts +0 -2
- package/src/components/chart/composite/rasterizer.ts +10 -9
- package/src/components/chart/composite/renderers.test.ts +108 -2
- package/src/components/chart/composite/scene.test.ts +36 -0
- package/src/components/chart/composite/scene.ts +5 -2
- package/src/components/chart/composite/text-renderer.ts +37 -25
- package/src/components/chart/composite/time-axis.test.ts +243 -0
- package/src/components/chart/composite/time-axis.ts +608 -0
- package/src/components/chart/composite/types.ts +12 -1
- package/src/components/chart/core/data.ts +2 -159
- package/src/components/chart/core/date-window.ts +6 -225
- package/src/components/chart/core/palette.ts +1 -12
- package/src/components/chart/core/pointer.ts +0 -142
- package/src/components/chart/core/types.ts +1 -58
- package/src/components/chart/cursor-motion.ts +2 -4
- package/src/components/chart/indicators/types.ts +0 -9
- package/src/components/chart/market-session.ts +0 -11
- package/src/components/chart/native/kitty/protocol.ts +1 -1
- package/src/components/chart/native/raster/layout.ts +3 -10
- package/src/components/chart/static/chart/axis-overlays.test.tsx +64 -0
- package/src/components/chart/static/chart/axis-overlays.tsx +59 -14
- package/src/components/chart/static/chart/surface.tsx +1 -2
- package/src/components/command-bar/action-runtime.ts +2 -2
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +2 -2
- package/src/components/command-bar/panel/index.tsx +11 -9
- package/src/components/command-bar/routes/ticker-search/actions.ts +2 -2
- package/src/components/command-bar/surface/index.tsx +2 -2
- package/src/components/command-bar/workflow/body.tsx +3 -3
- package/src/components/command-bar/workflow/collection-actions.ts +2 -2
- package/src/components/command-bar/workflow/coordinator.ts +2 -2
- package/src/components/command-bar/workflow/field-row.tsx +25 -11
- package/src/components/command-bar/workflow/tickers.ts +2 -2
- package/src/components/feed-data-table/stack-view.test.tsx +28 -36
- package/src/components/feed-data-table/stack-view.tsx +3 -1
- package/src/components/layout/detached-pane-shell.tsx +6 -6
- package/src/components/layout/header.tsx +13 -9
- package/src/components/layout/pane/content.test.tsx +42 -3
- package/src/components/layout/pane/content.tsx +3 -1
- package/src/components/layout/pane/footer/index.test.tsx +45 -2
- package/src/components/layout/pane/footer/registration.tsx +3 -1
- package/src/components/layout/shell/index.tsx +1 -2
- package/src/components/layout/shell/native/surfaces.ts +1 -1
- package/src/components/layout/shell/native/window-state.ts +1 -1
- package/src/components/layout/status-bar.tsx +12 -8
- package/src/components/layout/window-controls.tsx +8 -6
- package/src/components/onboarding/onboarding-wizard.tsx +3 -1
- package/src/components/pane-settings-dialog/desktop.tsx +0 -2
- package/src/components/pane-settings-dialog.tsx +0 -2
- package/src/components/pane-template-wizard.tsx +10 -9
- package/src/components/price-performance.tsx +2 -113
- package/src/components/price-sparkline/model.ts +15 -17
- package/src/components/price-sparkline/view.tsx +8 -7
- package/src/components/speedometer-gauge/desktop.tsx +2 -1
- package/src/components/speedometer-gauge/index.tsx +0 -2
- package/src/components/speedometer-gauge/terminal.tsx +24 -5
- package/src/components/ticker/badge/index.tsx +1 -18
- package/src/components/ui/data-table/opentui/index.tsx +3 -3
- package/src/components/ui/frame.tsx +1 -2
- package/src/components/ui/page-stack-view.test.tsx +126 -0
- package/src/components/ui/page-stack-view.tsx +24 -12
- package/src/components/ui/tabs.tsx +7 -3
- package/src/components/ui/ui.test.tsx +23 -2
- package/src/components/use-external-link-footer.ts +4 -2
- package/src/core/app-service-ports.ts +46 -0
- package/src/core/app-services.test.ts +66 -0
- package/src/core/app-services.ts +17 -15
- package/src/data/config/chart-settings.ts +3 -10
- package/src/data/config/store/index.test.ts +99 -2
- package/src/data/config/store/migrations.ts +278 -0
- package/src/data/config/store/normalize.ts +44 -186
- package/src/data/resource-store.ts +73 -12
- package/src/data/sqlite/cache.test.ts +104 -15
- package/src/i18n/index.test.ts +17 -0
- package/src/i18n/index.ts +23 -6
- package/src/i18n/ja.ts +13 -0
- package/src/i18n/ko.ts +13 -0
- package/src/i18n/react.ts +6 -0
- package/src/i18n/zh-cn.ts +13 -0
- package/src/i18n/zh-tw.ts +13 -0
- package/src/market-data/coordinator/auxiliary.ts +7 -3
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/index.test.ts +26 -0
- package/src/market-data/coordinator/index.ts +11 -5
- package/src/market-data/coordinator/quotes.ts +4 -40
- package/src/market-data/coordinator/subscriptions.test.ts +89 -1
- package/src/market-data/hooks.tsx +47 -1
- package/src/market-data/market/status.ts +6 -6
- package/src/market-data/performance.ts +1 -1
- package/src/market-data/quote-subscription-target.test.ts +37 -0
- package/src/market-data/quote-subscription-target.ts +60 -0
- package/src/market-data/quotes/freshness.ts +1 -0
- package/src/market-data/quotes/resolution.ts +4 -0
- package/src/market-data/request-types.ts +3 -3
- package/src/news/aggregator.test.ts +97 -1
- package/src/news/aggregator.ts +100 -57
- package/src/news/hooks.test.tsx +64 -0
- package/src/news/hooks.ts +18 -25
- package/src/plugins/builtin/account-management/footer.ts +4 -2
- package/src/plugins/builtin/account-management/pane.tsx +9 -4
- package/src/plugins/builtin/ai/agent-history.ts +11 -7
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +0 -5
- package/src/plugins/builtin/ai/ask-ai.test.tsx +3 -4
- package/src/plugins/builtin/ai/index.test.ts +2 -2
- package/src/plugins/builtin/ai/index.tsx +10 -11
- package/src/plugins/builtin/ai/pane-settings.ts +1 -1
- package/src/plugins/builtin/ai/pi/runtime.ts +6 -5
- package/src/plugins/builtin/ai/providers.ts +1 -9
- package/src/plugins/builtin/ai/runner.ts +0 -6
- package/src/plugins/builtin/ai/screener/footer.ts +4 -1
- package/src/plugins/builtin/ai/screener/pane.test.tsx +9 -9
- package/src/plugins/builtin/ai/workspace/model.ts +2 -27
- package/src/plugins/builtin/ai/workspace/pane.tsx +2 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +3 -2
- package/src/plugins/builtin/broker-manager/index.tsx +4 -2
- package/src/plugins/builtin/chart-composer/editor/controller.ts +643 -0
- package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +134 -0
- package/src/plugins/builtin/chart-composer/editor/model.test.ts +85 -0
- package/src/plugins/builtin/chart-composer/editor/model.ts +292 -0
- package/src/plugins/builtin/chart-composer/editor/opentui-view.tsx +108 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +65 -947
- package/src/plugins/builtin/chart-composer/index.tsx +0 -6
- package/src/plugins/builtin/chart-composer/pane.tsx +69 -36
- package/src/plugins/builtin/chart-composer/presets.ts +1 -19
- package/src/plugins/builtin/chart-composer/settings.ts +1 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +1 -1
- package/src/plugins/builtin/chat/content/shortcuts.ts +0 -1
- package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
- package/src/plugins/builtin/chat/controller/persistence.ts +2 -0
- package/src/plugins/builtin/chat/controller/session.test.ts +25 -0
- package/src/plugins/builtin/chat/controller/session.ts +2 -0
- package/src/plugins/builtin/chat/controller/state.ts +7 -0
- package/src/plugins/builtin/chat/controller.test.ts +73 -20
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -0
- package/src/plugins/builtin/cloud-tweets/footer.ts +9 -28
- package/src/plugins/builtin/cloud-tweets/pane.tsx +0 -5
- package/src/plugins/builtin/cloud-tweets/table.tsx +12 -17
- package/src/plugins/builtin/correlation/compute.ts +4 -10
- package/src/plugins/builtin/econ/index.tsx +17 -19
- package/src/plugins/builtin/holders/types.ts +0 -1
- package/src/plugins/builtin/insider/index.tsx +6 -31
- package/src/plugins/builtin/news/index.tsx +5 -7
- package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +6 -8
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -11
- package/src/plugins/builtin/news/wire/read-state.test.ts +7 -0
- package/src/plugins/builtin/news/wire/read-state.ts +18 -28
- package/src/plugins/builtin/news/wire/rss/parser.ts +1 -11
- package/src/plugins/builtin/options/footer.test.ts +115 -0
- package/src/plugins/builtin/options/footer.ts +110 -0
- package/src/plugins/builtin/options/live-quotes.test.ts +238 -0
- package/src/plugins/builtin/options/live-quotes.ts +147 -0
- package/src/plugins/builtin/options/view.test.tsx +71 -1
- package/src/plugins/builtin/options/view.tsx +39 -24
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +103 -117
- package/src/plugins/builtin/portfolio-list/cli/render.ts +11 -5
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -135
- package/src/plugins/builtin/portfolio-list/header.tsx +9 -4
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +6 -1
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +4 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +24 -52
- package/src/plugins/builtin/sec/filing-content.test.ts +41 -0
- package/src/plugins/builtin/sec/filing-content.ts +94 -0
- package/src/plugins/builtin/sec/index.tsx +21 -104
- package/src/plugins/builtin/sectors/sector-model.ts +1 -7
- package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -0
- package/src/plugins/builtin/shared/pane-footer.ts +82 -0
- package/src/plugins/builtin/shared/read-state.ts +64 -3
- package/src/plugins/builtin/substack/read-state.ts +16 -41
- package/src/plugins/builtin/thirteenf/pane.tsx +24 -73
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +10 -10
- package/src/plugins/builtin/yield-curve/index.tsx +11 -9
- package/src/plugins/ibkr/dialogs.tsx +3 -3
- package/src/plugins/ibkr/gateway/fundamentals.ts +1 -1
- package/src/plugins/ibkr/gateway/history-requests.ts +2 -2
- package/src/plugins/ibkr/gateway/history.ts +2 -2
- package/src/plugins/ibkr/gateway/selection.ts +2 -2
- package/src/plugins/ibkr/gateway/service/index.ts +2 -2
- package/src/plugins/ibkr/gateway/service/native.ts +2 -2
- package/src/plugins/plugin-persistence.ts +3 -4
- package/src/plugins/prediction-markets/controller/keyboard.ts +1 -1
- package/src/plugins/prediction-markets/controller/live-updates.ts +6 -5
- package/src/plugins/prediction-markets/detail/book.tsx +2 -2
- package/src/plugins/prediction-markets/detail/outcomes.tsx +3 -1
- package/src/plugins/prediction-markets/detail/pane.tsx +3 -1
- package/src/plugins/prediction-markets/detail/trades.tsx +3 -3
- package/src/plugins/registry/context.ts +3 -4
- package/src/plugins/registry/index.ts +5 -6
- package/src/react/input.test.ts +126 -3
- package/src/react/input.ts +120 -1
- package/src/remote/app-host.tsx +2 -13
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +44 -60
- package/src/renderers/electrobun/bun/desktop/capability-bridge.ts +15 -13
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +26 -22
- package/src/renderers/electrobun/bun/desktop/http-fetch.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +11 -6
- package/src/renderers/electrobun/bun/desktop/media.ts +5 -3
- package/src/renderers/electrobun/bun/desktop/plugin-state.ts +21 -22
- package/src/renderers/electrobun/bun/desktop/window-controls.ts +3 -1
- package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +18 -18
- package/src/renderers/electrobun/bun/index.ts +123 -83
- package/src/renderers/electrobun/shared/protocol.ts +146 -7
- package/src/renderers/electrobun/view/app-services.ts +5 -8
- package/src/renderers/electrobun/view/backend-rpc.ts +18 -8
- package/src/renderers/electrobun/view/broker-remote-client.ts +2 -2
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +5 -22
- package/src/renderers/electrobun/view/config-host.ts +1 -1
- package/src/renderers/electrobun/view/context-menu.ts +1 -17
- package/src/renderers/electrobun/view/data-table/index.tsx +0 -1
- package/src/renderers/electrobun/view/data-table/row.tsx +0 -4
- package/src/renderers/electrobun/view/desktop/control-styles.ts +37 -34
- package/src/renderers/electrobun/view/desktop/controls.tsx +36 -33
- package/src/renderers/electrobun/view/desktop/list-view.tsx +15 -12
- package/src/renderers/electrobun/view/desktop/popover.tsx +2 -3
- package/src/renderers/electrobun/view/dialog-host.tsx +2 -3
- package/src/renderers/electrobun/view/fatal-screen.tsx +0 -1
- package/src/renderers/electrobun/view/host/box.tsx +0 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +0 -1
- package/src/renderers/electrobun/view/host/input.tsx +0 -1
- package/src/renderers/electrobun/view/host/media-surface.tsx +0 -1
- package/src/renderers/electrobun/view/host/native.ts +0 -1
- package/src/renderers/electrobun/view/host/scroll-box.tsx +0 -1
- package/src/renderers/electrobun/view/host/tabs.tsx +0 -1
- package/src/renderers/electrobun/view/host/text.tsx +0 -1
- package/src/renderers/electrobun/view/http-fetch.ts +3 -11
- package/src/renderers/electrobun/view/input-host.tsx +10 -53
- package/src/renderers/electrobun/view/key-event.ts +0 -1
- package/src/renderers/electrobun/view/main.tsx +3 -3
- package/src/renderers/electrobun/view/native-renderer.ts +0 -1
- package/src/renderers/electrobun/view/native-stubs/backend-rpc.ts +13 -1
- package/src/renderers/electrobun/view/native-stubs/chart/surface-manager.ts +11 -0
- package/src/renderers/electrobun/view/native-stubs/native-stubs.test.ts +47 -0
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +6 -44
- package/src/renderers/electrobun/view/remote/persistence.ts +6 -2
- package/src/renderers/electrobun/view/remote/quote-subscription-registry.test.ts +86 -0
- package/src/renderers/electrobun/view/remote/quote-subscription-registry.ts +72 -0
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +2 -2
- package/src/renderers/electrobun/view/toast-host.tsx +0 -1
- package/src/renderers/electrobun/view/ui-host.tsx +1 -2
- package/src/renderers/electrobun/view/update-host.ts +1 -1
- package/src/renderers/opentui/chart-surface.tsx +2 -1
- package/src/renderers/opentui/dialog-host.tsx +20 -4
- package/src/renderers/opentui/image/loader.ts +12 -2
- package/src/renderers/opentui/input-host.tsx +7 -49
- package/src/renderers/opentui/start.tsx +2 -0
- package/src/sources/gloomberb-cloud/history-quality.ts +44 -0
- package/src/sources/gloomberb-cloud/index.test.ts +173 -0
- package/src/sources/gloomberb-cloud/index.ts +42 -20
- package/src/sources/gloomberb-cloud/normalizers.ts +9 -3
- package/src/sources/provider-router/cache.ts +1 -1
- package/src/sources/provider-router/document-routes.ts +10 -5
- package/src/sources/provider-router/financials.test.ts +14 -0
- package/src/sources/provider-router/financials.ts +6 -1
- package/src/sources/provider-router/history.test.ts +163 -1
- package/src/sources/provider-router/history.ts +278 -347
- package/src/sources/provider-router/index.ts +2 -2
- package/src/sources/provider-router/routing.test.ts +39 -0
- package/src/sources/provider-router/routing.ts +24 -11
- package/src/sources/provider-router/supplemental.ts +37 -17
- package/src/sources/sec-edgar/content.ts +2 -12
- package/src/sources/sec-edgar.ts +2 -13
- package/src/sources/yahoo-finance/history.ts +2 -2
- package/src/sources/yahoo-finance/options.ts +5 -0
- package/src/sources/yahoo-finance.ts +2 -2
- package/src/state/app/bootstrap.ts +2 -2
- package/src/state/app/context/index.tsx +2 -2
- package/src/state/hooks/quote-streaming.ts +66 -1
- package/src/state/hooks/session-snapshot.ts +2 -2
- package/src/state/selectors.ts +0 -9
- package/src/sync/controller.test.ts +98 -0
- package/src/sync/controller.ts +29 -5
- package/src/sync/react.ts +2 -2
- package/src/sync/types.ts +2 -2
- package/src/theme/colors.test.ts +10 -0
- package/src/theme/colors.ts +75 -78
- package/src/theme/theme-context.test.tsx +67 -0
- package/src/theme/theme-context.tsx +9 -5
- package/src/tickers/open-target.ts +2 -2
- package/src/tickers/search/upsert.ts +2 -2
- package/src/time-series/alignment.ts +0 -7
- package/src/time-series/chart-data.ts +145 -0
- package/src/time-series/date-window.ts +44 -0
- package/src/time-series/history-window.ts +21 -0
- package/src/time-series/hooks.test.ts +59 -0
- package/src/time-series/hooks.ts +33 -12
- package/src/time-series/market-resolution.ts +2 -2
- package/src/time-series/market.ts +1 -1
- package/src/time-series/range.ts +9 -0
- package/src/{components/chart/core → time-series}/resolution.ts +3 -102
- package/src/time-series/resolve.test.ts +203 -1
- package/src/time-series/resolve.ts +96 -18
- package/src/time-series/spec-studies.test.ts +15 -0
- package/src/time-series/spec.ts +2 -2
- package/src/time-series/studies.ts +5 -2
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.test.tsx +358 -0
- package/src/time-series/use-chart-resolution.ts +46 -4
- package/src/types/broker.ts +2 -2
- package/src/types/data-provider.ts +3 -3
- package/src/types/financials.ts +12 -0
- package/src/types/plugin.ts +2 -2
- package/src/ui/context-menu.tsx +3 -2
- package/src/ui/dialog.tsx +2 -2
- package/src/utils/html-entities.ts +3 -5
- package/src/utils/main-thread-monitor.ts +1 -1
- package/src/utils/price-history.ts +5 -5
- package/src/version.ts +3 -1
- package/src/components/chart/core/viewport.test.ts +0 -8
- package/src/components/chart/core/viewport.ts +0 -24
- package/src/time-series/index.ts +0 -14
- /package/src/{components/chart/core → time-series}/resolution.test.ts +0 -0
package/src/time-series/hooks.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { instrumentFromTicker } from "../market-data/request-types";
|
|
|
5
5
|
import { useAssetData } from "../plugins/runtime";
|
|
6
6
|
import { useAppSelector } from "../state/app/context";
|
|
7
7
|
import type { FredSeriesRequest } from "../data/fred-series";
|
|
8
|
+
import type { TickerRecord } from "../types/ticker";
|
|
8
9
|
import type { ChartSpec } from "./types";
|
|
9
10
|
import {
|
|
10
11
|
useChartResolution,
|
|
@@ -22,24 +23,44 @@ async function loadFred(request: FredSeriesRequest) {
|
|
|
22
23
|
);
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
export function hydrateChartSpecInstruments(
|
|
27
|
+
spec: ChartSpec,
|
|
28
|
+
tickers: ReadonlyMap<string, TickerRecord>,
|
|
29
|
+
): ChartSpec {
|
|
30
|
+
let changed = false;
|
|
31
|
+
const series = spec.series.map((entry) => {
|
|
32
|
+
if (entry.source.kind !== "security" || entry.source.instrument.exchange?.trim()) {
|
|
33
|
+
return entry;
|
|
34
|
+
}
|
|
35
|
+
const symbol = entry.source.instrument.symbol.trim().toUpperCase();
|
|
36
|
+
const instrument = instrumentFromTicker(tickers.get(symbol), symbol);
|
|
37
|
+
if (!instrument?.exchange) return entry;
|
|
38
|
+
changed = true;
|
|
39
|
+
return {
|
|
40
|
+
...entry,
|
|
41
|
+
source: {
|
|
42
|
+
...entry.source,
|
|
43
|
+
instrument: {
|
|
44
|
+
...instrument,
|
|
45
|
+
...entry.source.instrument,
|
|
46
|
+
exchange: instrument.exchange,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
return changed ? { ...spec, series } : spec;
|
|
52
|
+
}
|
|
53
|
+
|
|
25
54
|
export function useResolvedChartSpec(
|
|
26
55
|
spec: ChartSpec,
|
|
27
56
|
options: UseChartResolutionOptions = {},
|
|
28
57
|
): UseChartResolutionResult {
|
|
29
58
|
const dataProvider = useAssetData();
|
|
30
59
|
const tickers = useAppSelector((state) => state.tickers);
|
|
31
|
-
const hydratedSpec = useMemo
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const symbol = entry.source.instrument.symbol.trim().toUpperCase();
|
|
36
|
-
const ticker = tickers.get(symbol);
|
|
37
|
-
const instrument = instrumentFromTicker(ticker, symbol);
|
|
38
|
-
return instrument
|
|
39
|
-
? { ...entry, source: { ...entry.source, instrument: { ...instrument, ...entry.source.instrument } } }
|
|
40
|
-
: entry;
|
|
41
|
-
}),
|
|
42
|
-
}), [spec, tickers]);
|
|
60
|
+
const hydratedSpec = useMemo(
|
|
61
|
+
() => hydrateChartSpecInstruments(spec, tickers),
|
|
62
|
+
[spec, tickers],
|
|
63
|
+
);
|
|
43
64
|
const sources = useMemo(() => ({ dataProvider, loadFredSeries: loadFred }), [dataProvider]);
|
|
44
65
|
return useChartResolution(hydratedSpec, sources, options);
|
|
45
66
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CHART_RESOLUTION_STEP_MS,
|
|
3
3
|
type ManualChartResolution,
|
|
4
|
-
} from "
|
|
4
|
+
} from "./resolution";
|
|
5
5
|
import { isMarketFieldId } from "./field-catalog";
|
|
6
6
|
import type { ChartSeriesSpec, SeriesPeriod } from "./types";
|
|
7
7
|
|
|
@@ -27,7 +27,7 @@ export function isResolutionFineEnoughForMarketPeriod(
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/** Returns the finest fetch cadence required by explicit market periods. */
|
|
30
|
-
|
|
30
|
+
function finestExplicitMarketPeriodResolution(
|
|
31
31
|
series: readonly ChartSeriesSpec[],
|
|
32
32
|
): ManualChartResolution | null {
|
|
33
33
|
let finest: ManualChartResolution | null = null;
|
|
@@ -41,7 +41,7 @@ interface AggregatedPricePoint {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/** Aggregates OHLCV correctly: first open, max high, min low, last close, summed volume. */
|
|
44
|
-
|
|
44
|
+
function aggregatePriceHistory(
|
|
45
45
|
points: readonly PricePoint[],
|
|
46
46
|
period: SeriesPeriod,
|
|
47
47
|
): PricePoint[] {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type TimeRange = "1D" | "1W" | "1M" | "3M" | "6M" | "1Y" | "5Y" | "ALL";
|
|
2
|
+
export type ChartResolution = "auto" | "1m" | "5m" | "15m" | "30m" | "45m" | "1h" | "1d" | "1wk" | "1mo";
|
|
3
|
+
|
|
4
|
+
export interface ChartDateWindow {
|
|
5
|
+
start: Date | null;
|
|
6
|
+
end: Date | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const TIME_RANGES: TimeRange[] = ["1D", "1W", "1M", "3M", "6M", "1Y", "5Y", "ALL"];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ChartResolution, TimeRange } from "./
|
|
2
|
-
import { TIME_RANGES } from "./
|
|
1
|
+
import type { ChartResolution, TimeRange } from "./range";
|
|
2
|
+
import { TIME_RANGES } from "./range";
|
|
3
3
|
import { isDateWindowWithinTimeRange } from "./date-window";
|
|
4
4
|
|
|
5
5
|
export type ManualChartResolution = Exclude<ChartResolution, "auto">;
|
|
@@ -71,10 +71,6 @@ export const CHART_RESOLUTION_STEP_MS: Record<ManualChartResolution, number> = {
|
|
|
71
71
|
"1mo": 30 * 24 * 60 * 60_000,
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
export function getChartResolutionStepMs(resolution: ChartResolution): number | null {
|
|
75
|
-
return resolution === "auto" ? null : CHART_RESOLUTION_STEP_MS[resolution];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
74
|
const CHART_RESOLUTION_POINTS_PER_DAY: Record<ManualChartResolution, number> = {
|
|
79
75
|
"1m": 390,
|
|
80
76
|
"5m": 78,
|
|
@@ -88,22 +84,6 @@ const CHART_RESOLUTION_POINTS_PER_DAY: Record<ManualChartResolution, number> = {
|
|
|
88
84
|
};
|
|
89
85
|
|
|
90
86
|
const TIME_RANGE_INDEX = new Map(TIME_RANGE_ORDER.map((range, index) => [range, index]));
|
|
91
|
-
const RANGE_PRESETS_BY_RESOLUTION = TIME_RANGE_ORDER.reduce<Record<ManualChartResolution, TimeRange[]>>((acc, range) => {
|
|
92
|
-
const resolution = RANGE_PRESET_RESOLUTION[range];
|
|
93
|
-
acc[resolution] ??= [];
|
|
94
|
-
acc[resolution].push(range);
|
|
95
|
-
return acc;
|
|
96
|
-
}, {
|
|
97
|
-
"1m": [],
|
|
98
|
-
"5m": [],
|
|
99
|
-
"15m": [],
|
|
100
|
-
"30m": [],
|
|
101
|
-
"45m": [],
|
|
102
|
-
"1h": [],
|
|
103
|
-
"1d": [],
|
|
104
|
-
"1wk": [],
|
|
105
|
-
"1mo": [],
|
|
106
|
-
});
|
|
107
87
|
|
|
108
88
|
function getTimeRangeIndex(range: TimeRange): number {
|
|
109
89
|
return TIME_RANGE_INDEX.get(range) ?? 0;
|
|
@@ -133,14 +113,6 @@ export function getPresetResolution(range: TimeRange): ManualChartResolution {
|
|
|
133
113
|
return RANGE_PRESET_RESOLUTION[range];
|
|
134
114
|
}
|
|
135
115
|
|
|
136
|
-
function getManualResolutionOrderIndex(resolution: ManualChartResolution): number {
|
|
137
|
-
return CHART_RESOLUTION_ORDER.indexOf(resolution);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function getPresetBufferRange(range: TimeRange): TimeRange {
|
|
141
|
-
return RANGE_PRELOAD_BUFFER[range];
|
|
142
|
-
}
|
|
143
|
-
|
|
144
116
|
export function getNextBufferRange(range: TimeRange): TimeRange {
|
|
145
117
|
return RANGE_PRELOAD_BUFFER[range];
|
|
146
118
|
}
|
|
@@ -201,12 +173,6 @@ export function intersectChartResolutionSupport(
|
|
|
201
173
|
}));
|
|
202
174
|
}
|
|
203
175
|
|
|
204
|
-
export function buildChartResolutionSupportMap(
|
|
205
|
-
support: readonly ChartResolutionSupport[],
|
|
206
|
-
): ReadonlyMap<ManualChartResolution, TimeRange> {
|
|
207
|
-
return new Map(normalizeChartResolutionSupport(support).map((entry) => [entry.resolution, entry.maxRange] as const));
|
|
208
|
-
}
|
|
209
|
-
|
|
210
176
|
export function getSupportMaxRange(
|
|
211
177
|
support: readonly ChartResolutionSupport[] | ReadonlyMap<ManualChartResolution, TimeRange>,
|
|
212
178
|
resolution: ManualChartResolution,
|
|
@@ -221,11 +187,7 @@ function minTimeRange(left: TimeRange, right: TimeRange): TimeRange {
|
|
|
221
187
|
return compareTimeRange(left, right) <= 0 ? left : right;
|
|
222
188
|
}
|
|
223
189
|
|
|
224
|
-
|
|
225
|
-
return compareTimeRange(left, right) >= 0 ? left : right;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export function isTimeRangeAtOrBelow(candidate: TimeRange, maxRange: TimeRange): boolean {
|
|
190
|
+
function isTimeRangeAtOrBelow(candidate: TimeRange, maxRange: TimeRange): boolean {
|
|
229
191
|
return compareTimeRange(candidate, maxRange) <= 0;
|
|
230
192
|
}
|
|
231
193
|
|
|
@@ -255,43 +217,6 @@ export function isRangePresetSupported(
|
|
|
255
217
|
return maxRange !== null && isTimeRangeAtOrBelow(range, maxRange);
|
|
256
218
|
}
|
|
257
219
|
|
|
258
|
-
export function getWidestPresetForResolution(
|
|
259
|
-
resolution: ManualChartResolution,
|
|
260
|
-
maxRange: TimeRange,
|
|
261
|
-
): TimeRange {
|
|
262
|
-
const presets = RANGE_PRESETS_BY_RESOLUTION[resolution] ?? [];
|
|
263
|
-
const supported = presets.filter((range) => isTimeRangeAtOrBelow(range, maxRange));
|
|
264
|
-
if (supported.length > 0) {
|
|
265
|
-
return supported[supported.length - 1]!;
|
|
266
|
-
}
|
|
267
|
-
const fallback = TIME_RANGE_ORDER.filter((range) => isTimeRangeAtOrBelow(range, maxRange));
|
|
268
|
-
return fallback[fallback.length - 1] ?? "1D";
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export function getBestSupportedResolutionForPreset(
|
|
272
|
-
range: TimeRange,
|
|
273
|
-
support: readonly ChartResolutionSupport[] | ReadonlyMap<ManualChartResolution, TimeRange>,
|
|
274
|
-
preferredResolution = getPresetResolution(range),
|
|
275
|
-
): ManualChartResolution | null {
|
|
276
|
-
const supportedResolutions = CHART_RESOLUTION_ORDER
|
|
277
|
-
.filter((resolution): resolution is ManualChartResolution => resolution !== "auto")
|
|
278
|
-
.filter((resolution) => {
|
|
279
|
-
const maxRange = getSupportMaxRange(support, resolution);
|
|
280
|
-
return maxRange !== null && isTimeRangeAtOrBelow(range, maxRange);
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
if (supportedResolutions.length === 0) return null;
|
|
284
|
-
if (supportedResolutions.includes(preferredResolution)) return preferredResolution;
|
|
285
|
-
|
|
286
|
-
const preferredIndex = getManualResolutionOrderIndex(preferredResolution);
|
|
287
|
-
const coarserResolution = supportedResolutions.find((resolution) => (
|
|
288
|
-
getManualResolutionOrderIndex(resolution) > preferredIndex
|
|
289
|
-
));
|
|
290
|
-
if (coarserResolution) return coarserResolution;
|
|
291
|
-
|
|
292
|
-
return supportedResolutions[supportedResolutions.length - 1] ?? null;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
220
|
export function getBestSupportedResolutionForVisibleWindow(
|
|
296
221
|
window: { start: Date | null; end: Date | null } | null,
|
|
297
222
|
support: readonly ChartResolutionSupport[] | ReadonlyMap<ManualChartResolution, TimeRange>,
|
|
@@ -322,27 +247,3 @@ export function getBestSupportedResolutionForVisibleWindow(
|
|
|
322
247
|
|
|
323
248
|
return supportedResolutions[0] ?? null;
|
|
324
249
|
}
|
|
325
|
-
|
|
326
|
-
export function getNextFallbackResolution(
|
|
327
|
-
range: TimeRange,
|
|
328
|
-
currentResolution: ManualChartResolution,
|
|
329
|
-
support: readonly ChartResolutionSupport[] | ReadonlyMap<ManualChartResolution, TimeRange>,
|
|
330
|
-
): ChartResolution | null {
|
|
331
|
-
const currentIndex = getManualResolutionOrderIndex(currentResolution);
|
|
332
|
-
const nextResolution = CHART_RESOLUTION_ORDER
|
|
333
|
-
.filter((resolution): resolution is ManualChartResolution => resolution !== "auto")
|
|
334
|
-
.find((resolution) => (
|
|
335
|
-
getManualResolutionOrderIndex(resolution) > currentIndex
|
|
336
|
-
&& (() => {
|
|
337
|
-
const maxRange = getSupportMaxRange(support, resolution);
|
|
338
|
-
return maxRange !== null && isTimeRangeAtOrBelow(range, maxRange);
|
|
339
|
-
})()
|
|
340
|
-
));
|
|
341
|
-
|
|
342
|
-
return nextResolution ?? "auto";
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
export function getCompatibleBufferRange(presetRange: TimeRange, maxRange: TimeRange | null): TimeRange {
|
|
346
|
-
const preloadRange = getPresetBufferRange(presetRange);
|
|
347
|
-
return maxRange ? clampTimeRangeToMaxRange(preloadRange, maxRange) : preloadRange;
|
|
348
|
-
}
|
|
@@ -111,6 +111,145 @@ describe("resolveChartSpecData", () => {
|
|
|
111
111
|
]);
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
+
test("keeps the snapshot exchange when a newer quote omits it", async () => {
|
|
115
|
+
const historyExchanges: string[] = [];
|
|
116
|
+
const source = {
|
|
117
|
+
kind: "security" as const,
|
|
118
|
+
instrument: { symbol: "SNDK" },
|
|
119
|
+
fieldId: "market.ohlcv",
|
|
120
|
+
};
|
|
121
|
+
const provider = createTestDataProvider({
|
|
122
|
+
getTickerFinancials: async () => ({
|
|
123
|
+
...emptyFinancials(),
|
|
124
|
+
quote: {
|
|
125
|
+
symbol: "SNDK",
|
|
126
|
+
price: 1_240,
|
|
127
|
+
currency: "USD",
|
|
128
|
+
change: 20,
|
|
129
|
+
changePercent: 1.64,
|
|
130
|
+
lastUpdated: Date.parse("2026-07-30T15:25:00Z"),
|
|
131
|
+
listingExchangeName: "XNAS",
|
|
132
|
+
},
|
|
133
|
+
}),
|
|
134
|
+
getPriceHistoryForResolution: async (_symbol, exchange) => {
|
|
135
|
+
historyExchanges.push(exchange);
|
|
136
|
+
return [{
|
|
137
|
+
date: new Date("2026-07-30T15:20:00Z"),
|
|
138
|
+
open: 1_235,
|
|
139
|
+
high: 1_242,
|
|
140
|
+
low: 1_233,
|
|
141
|
+
close: 1_240,
|
|
142
|
+
}];
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
const spec: ChartSpec = {
|
|
146
|
+
version: CHART_SPEC_VERSION,
|
|
147
|
+
viewport: { range: "1D", resolution: "5m" },
|
|
148
|
+
panels: [{ id: "main" }],
|
|
149
|
+
series: [{
|
|
150
|
+
id: "price",
|
|
151
|
+
source,
|
|
152
|
+
style: "candles",
|
|
153
|
+
transform: "raw",
|
|
154
|
+
axis: "left",
|
|
155
|
+
panelId: "main",
|
|
156
|
+
interpolation: "none",
|
|
157
|
+
}],
|
|
158
|
+
studies: [],
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const result = await resolveChartSpecData(spec, {
|
|
162
|
+
dataProvider: provider,
|
|
163
|
+
now: new Date("2026-07-30T15:30:00Z"),
|
|
164
|
+
quoteOverrides: new Map([[
|
|
165
|
+
chartQuoteOverrideKeyForSource(source),
|
|
166
|
+
{
|
|
167
|
+
symbol: "SNDK",
|
|
168
|
+
price: 1_245,
|
|
169
|
+
currency: "USD",
|
|
170
|
+
change: 25,
|
|
171
|
+
changePercent: 2.05,
|
|
172
|
+
lastUpdated: Date.parse("2026-07-30T15:26:00Z"),
|
|
173
|
+
},
|
|
174
|
+
]]),
|
|
175
|
+
loadFredSeries: async () => fredLoad(),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
expect(result.errors).toEqual([]);
|
|
179
|
+
expect(historyExchanges).toEqual(["XNAS"]);
|
|
180
|
+
expect(result.series[0]?.points.at(-1)?.date.toISOString())
|
|
181
|
+
.toBe("2026-07-30T15:26:00.000Z");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("resolves the exchange before selecting an adaptive Auto resolution", async () => {
|
|
185
|
+
const supportExchanges: string[] = [];
|
|
186
|
+
const historyRequests: Array<{ exchange: string; resolution: string }> = [];
|
|
187
|
+
const provider = createTestDataProvider({
|
|
188
|
+
getTickerFinancials: async () => ({
|
|
189
|
+
...emptyFinancials(),
|
|
190
|
+
quote: {
|
|
191
|
+
symbol: "SNDK",
|
|
192
|
+
price: 1_240,
|
|
193
|
+
currency: "USD",
|
|
194
|
+
change: 20,
|
|
195
|
+
changePercent: 1.64,
|
|
196
|
+
lastUpdated: Date.parse("2026-07-30T15:25:00Z"),
|
|
197
|
+
listingExchangeName: "XNAS",
|
|
198
|
+
},
|
|
199
|
+
}),
|
|
200
|
+
getChartResolutionSupport: (_symbol, exchange) => {
|
|
201
|
+
supportExchanges.push(exchange);
|
|
202
|
+
return exchange === "XNAS"
|
|
203
|
+
? [{ resolution: "5m", maxRange: "1W" }]
|
|
204
|
+
: [{ resolution: "1d", maxRange: "5Y" }];
|
|
205
|
+
},
|
|
206
|
+
getDetailedPriceHistory: async (_symbol, exchange, _start, _end, resolution) => {
|
|
207
|
+
historyRequests.push({ exchange, resolution });
|
|
208
|
+
return [{ date: new Date("2026-07-30T15:20:00Z"), close: 1_240 }];
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
const spec: ChartSpec = {
|
|
212
|
+
version: CHART_SPEC_VERSION,
|
|
213
|
+
viewport: { range: "1D", resolution: "auto" },
|
|
214
|
+
panels: [{ id: "main" }],
|
|
215
|
+
series: [{
|
|
216
|
+
id: "price",
|
|
217
|
+
source: {
|
|
218
|
+
kind: "security",
|
|
219
|
+
instrument: { symbol: "SNDK" },
|
|
220
|
+
fieldId: "market.close",
|
|
221
|
+
},
|
|
222
|
+
style: "line",
|
|
223
|
+
transform: "raw",
|
|
224
|
+
axis: "left",
|
|
225
|
+
panelId: "main",
|
|
226
|
+
interpolation: "none",
|
|
227
|
+
}],
|
|
228
|
+
studies: [],
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const result = await resolveChartSpecData(
|
|
232
|
+
spec,
|
|
233
|
+
{
|
|
234
|
+
dataProvider: provider,
|
|
235
|
+
now: new Date("2026-07-30T15:30:00Z"),
|
|
236
|
+
loadFredSeries: async () => fredLoad(),
|
|
237
|
+
},
|
|
238
|
+
new ChartResolveCache(),
|
|
239
|
+
{
|
|
240
|
+
autoViewport: {
|
|
241
|
+
start: new Date("2026-07-30T09:30:00Z"),
|
|
242
|
+
end: new Date("2026-07-30T15:30:00Z"),
|
|
243
|
+
},
|
|
244
|
+
targetPointCount: 100,
|
|
245
|
+
},
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
expect(result.errors).toEqual([]);
|
|
249
|
+
expect(supportExchanges).toEqual(["XNAS"]);
|
|
250
|
+
expect(historyRequests).toEqual([{ exchange: "XNAS", resolution: "5m" }]);
|
|
251
|
+
});
|
|
252
|
+
|
|
114
253
|
test("uses provider-default history as a valid fallback for Auto resolution", async () => {
|
|
115
254
|
let genericHistoryCalls = 0;
|
|
116
255
|
const provider = createTestDataProvider({
|
|
@@ -186,7 +325,7 @@ describe("resolveChartSpecData", () => {
|
|
|
186
325
|
expect(requests).toEqual([{ range: "1W", resolution: "5m" }]);
|
|
187
326
|
});
|
|
188
327
|
|
|
189
|
-
test("
|
|
328
|
+
test("keeps Auto zoom selection while loading a separately panned history window", async () => {
|
|
190
329
|
const detailedRequests: Array<{
|
|
191
330
|
start: string;
|
|
192
331
|
end: string;
|
|
@@ -238,6 +377,10 @@ describe("resolveChartSpecData", () => {
|
|
|
238
377
|
new ChartResolveCache(),
|
|
239
378
|
{
|
|
240
379
|
autoViewport: {
|
|
380
|
+
start: new Date("2025-03-10T00:00:00.000Z"),
|
|
381
|
+
end: new Date("2025-03-17T00:00:00.000Z"),
|
|
382
|
+
},
|
|
383
|
+
requestViewport: {
|
|
241
384
|
start: new Date("2025-01-10T00:00:00.000Z"),
|
|
242
385
|
end: new Date("2025-01-17T00:00:00.000Z"),
|
|
243
386
|
},
|
|
@@ -258,6 +401,64 @@ describe("resolveChartSpecData", () => {
|
|
|
258
401
|
});
|
|
259
402
|
});
|
|
260
403
|
|
|
404
|
+
test("keeps percent transforms and studies defined in a panned history window", async () => {
|
|
405
|
+
const provider = createTestDataProvider({
|
|
406
|
+
getTickerFinancials: async () => emptyFinancials(),
|
|
407
|
+
getDetailedPriceHistory: async () => [
|
|
408
|
+
{ date: new Date("2024-10-15T16:00:00.000Z"), close: 100 },
|
|
409
|
+
{ date: new Date("2024-10-16T16:00:00.000Z"), close: 110 },
|
|
410
|
+
],
|
|
411
|
+
});
|
|
412
|
+
const spec: ChartSpec = {
|
|
413
|
+
version: CHART_SPEC_VERSION,
|
|
414
|
+
viewport: { range: "3M", resolution: "1d" },
|
|
415
|
+
panels: [{ id: "main" }],
|
|
416
|
+
series: [{
|
|
417
|
+
id: "price",
|
|
418
|
+
source: {
|
|
419
|
+
kind: "security",
|
|
420
|
+
instrument: { symbol: "TEST", exchange: "NASDAQ" },
|
|
421
|
+
fieldId: "market.close",
|
|
422
|
+
},
|
|
423
|
+
style: "line",
|
|
424
|
+
transform: "percent",
|
|
425
|
+
axis: "left",
|
|
426
|
+
panelId: "main",
|
|
427
|
+
interpolation: "none",
|
|
428
|
+
}],
|
|
429
|
+
studies: [{
|
|
430
|
+
id: "sma",
|
|
431
|
+
kind: "sma",
|
|
432
|
+
inputSeriesIds: ["price"],
|
|
433
|
+
parameters: { period: 2 },
|
|
434
|
+
panelId: "main",
|
|
435
|
+
axis: "left",
|
|
436
|
+
}],
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
const result = await resolveChartSpecData(
|
|
440
|
+
spec,
|
|
441
|
+
{
|
|
442
|
+
dataProvider: provider,
|
|
443
|
+
now: new Date("2025-04-01T00:00:00.000Z"),
|
|
444
|
+
loadFredSeries: async () => fredLoad(),
|
|
445
|
+
},
|
|
446
|
+
new ChartResolveCache(),
|
|
447
|
+
{
|
|
448
|
+
requestViewport: {
|
|
449
|
+
start: new Date("2024-10-10T00:00:00.000Z"),
|
|
450
|
+
end: new Date("2024-10-17T00:00:00.000Z"),
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
expect(result.errors).toEqual([]);
|
|
456
|
+
expect(result.bufferedSeries?.find((series) => series.id === "price")?.points.map((point) => point.value))
|
|
457
|
+
.toEqual([0, 10]);
|
|
458
|
+
expect(result.bufferedSeries?.find((series) => series.id === "sma")?.points.map((point) => point.value))
|
|
459
|
+
.toEqual([5]);
|
|
460
|
+
});
|
|
461
|
+
|
|
261
462
|
test("resolves unrelated price, filed fundamental, and economic series on one chart", async () => {
|
|
262
463
|
const provider = createTestDataProvider({
|
|
263
464
|
getTickerFinancials: async (symbol) => symbol === "MSFT"
|
|
@@ -747,6 +948,7 @@ describe("resolveChartSpecData", () => {
|
|
|
747
948
|
expect(result.series[0]?.points.map((point) => point.value)).toEqual([15, 25]);
|
|
748
949
|
expect(result.legendSeries?.find((series) => series.id === "price")?.timeBasis)
|
|
749
950
|
.toMatchObject({ kind: "market", timeZone: "America/New_York" });
|
|
951
|
+
expect(result.timelineSeries?.map((series) => series.id)).toEqual(["price"]);
|
|
750
952
|
expect(result.series[0]?.timeBasis)
|
|
751
953
|
.toMatchObject({ kind: "market", timeZone: "America/New_York" });
|
|
752
954
|
});
|