gloomberb 0.16.4 → 0.16.5
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 +14 -91
- package/package.json +4 -1
- package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
- package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
- package/src/account/billing.ts +57 -0
- package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
- package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
- package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
- package/src/account/session.ts +16 -0
- package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
- package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
- package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
- package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
- package/src/api-client/data.ts +24 -2
- package/src/api-client/earnings.ts +6 -0
- package/src/api-client/futures-curve.ts +56 -0
- package/src/api-client/index.ts +4 -1
- package/src/api-client/market-discovery.ts +10 -1
- package/src/api-client/paths.ts +7 -0
- package/src/api-client/research-activity.ts +15 -10
- package/src/api-client/types.ts +17 -1
- package/src/api-client/yield-curves.ts +8 -0
- package/src/app/global-shortcuts.ts +15 -1
- package/src/app/pane-runtime/ticker-open-runtime.ts +7 -3
- package/src/architecture/core-builtin-allowlist.json +4 -13
- package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
- package/src/capabilities/chart-series.ts +11 -1
- package/src/cli/commands/crypto-hints.ts +7 -0
- package/src/cli/commands/fred-series.ts +61 -0
- package/src/cli/commands/market.ts +407 -104
- package/src/cli/commands/news-hints.ts +62 -0
- package/src/cli/commands/news-search.ts +53 -0
- package/src/cli/commands/options-leaps.ts +5 -2
- package/src/cli/commands/overview.ts +93 -20
- package/src/cli/commands/remote.ts +2 -1
- package/src/cli/commands/search.ts +82 -9
- package/src/cli/commands/system.ts +55 -8
- package/src/cli/commands/ticker.ts +88 -11
- package/src/cli/context.ts +45 -14
- package/src/cli/desktop-pane-shot.ts +59 -7
- package/src/cli/earnings-calendar.ts +71 -0
- package/src/cli/freshness.ts +18 -7
- package/src/cli/glossary.ts +429 -0
- package/src/cli/history-rows.ts +48 -7
- package/src/cli/index-roots.ts +7 -0
- package/src/cli/index.ts +21 -7
- package/src/cli/known-gaps.ts +27 -0
- package/src/cli/listing-arg.ts +417 -56
- package/src/cli/not-a-ticker.ts +12 -5
- package/src/cli/pane-functions/access-gate.ts +5 -0
- package/src/cli/pane-functions/capabilities.ts +3 -2
- package/src/cli/pane-functions/catalog.ts +35 -5
- package/src/cli/pane-functions/data.ts +12 -8
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/dom.ts +20 -6
- package/src/cli/pane-functions/freshness.ts +363 -43
- package/src/cli/pane-functions/function-help.ts +12 -5
- package/src/cli/pane-functions/headless.ts +45 -17
- package/src/cli/pane-functions/index.ts +63 -10
- package/src/cli/pane-functions/market-session.ts +22 -8
- package/src/cli/pane-functions/options.ts +63 -22
- package/src/cli/pane-functions/report-notices.ts +25 -7
- package/src/cli/pane-functions/report.ts +15 -8
- package/src/cli/pane-functions/resolver.ts +49 -12
- package/src/cli/pane-functions/screenshot.ts +110 -23
- package/src/cli/report-tables.ts +3 -0
- package/src/cli/result.ts +4 -1
- package/src/cli/staged-tickers.ts +52 -0
- package/src/cli/symbol-args.ts +9 -0
- package/src/cli/symbol-list.ts +172 -0
- package/src/cli/ticker-resolution.ts +223 -30
- package/src/cli/types.ts +5 -0
- package/src/components/chart/composite/axis-overlays.tsx +6 -2
- package/src/components/chart/composite/composite-chart.tsx +40 -6
- package/src/components/chart/composite/legend.tsx +49 -2
- package/src/components/chart/composite/panel-surface.tsx +44 -17
- package/src/components/chart/composite/price-axis-labels.tsx +3 -1
- package/src/components/command-bar/panel/index.tsx +11 -3
- package/src/components/command-bar/panel/runtime.ts +3 -0
- package/src/components/command-bar/panel/types.ts +2 -0
- package/src/components/command-bar/routes/root/provider-search.ts +4 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
- package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
- package/src/components/command-bar/workflow/tickers.ts +23 -4
- package/src/components/layout/detached-pane-shell.tsx +9 -0
- package/src/components/layout/floating-pane.tsx +3 -0
- package/src/components/layout/header.tsx +20 -5
- package/src/components/layout/pane/content.tsx +7 -13
- package/src/components/layout/pane/footer/index.tsx +6 -2
- package/src/components/layout/pane/footer/model.ts +35 -1
- package/src/components/layout/pane/header.tsx +24 -1
- package/src/components/layout/pane/index.tsx +12 -2
- package/src/components/layout/pane/sidebar.tsx +78 -10
- package/src/components/layout/shell/active-drag.ts +21 -5
- package/src/components/layout/shell/drag/index.ts +39 -9
- package/src/components/layout/shell/drag/live.ts +61 -51
- package/src/components/layout/shell/drag/runtime.ts +54 -12
- package/src/components/layout/shell/index.tsx +25 -7
- package/src/components/layout/shell/menu.ts +5 -0
- package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
- package/src/components/layout/shell/pane/layers.tsx +192 -45
- package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
- package/src/components/markdown-text.tsx +62 -20
- package/src/components/metric-treemap/heat-surface.tsx +10 -1
- package/src/components/onboarding/account-step/form-panel.tsx +1 -1
- package/src/components/onboarding/account-step/index.tsx +1 -1
- package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
- package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
- package/src/components/onboarding/onboarding-keyboard.ts +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +2 -2
- package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
- package/src/components/onboarding/wizard-account.ts +2 -2
- package/src/components/pane-template-wizard.tsx +9 -1
- package/src/components/price-selector-dialog.tsx +11 -2
- package/src/components/sign-in-gate.tsx +3 -3
- package/src/components/ticker/list-table-view.tsx +24 -1
- package/src/components/ui/action-row.tsx +2 -1
- package/src/components/ui/button.tsx +7 -1
- package/src/components/ui/choice-dialog.tsx +6 -4
- package/src/components/ui/confirm-dialog.tsx +28 -18
- package/src/components/ui/data-table/index.tsx +17 -6
- package/src/components/ui/data-table/opentui/index.tsx +37 -6
- package/src/components/ui/data-table/types.ts +12 -0
- package/src/components/ui/dialog-actions.tsx +64 -0
- package/src/components/ui/display.tsx +17 -3
- package/src/components/ui/frame.tsx +35 -2
- package/src/components/ui/icon.tsx +2 -0
- package/src/components/ui/text-prompt-dialog.tsx +11 -9
- package/src/data/cached-query.ts +2 -0
- package/src/data/config/store/normalize.ts +7 -2
- package/src/data/ticker-repository.ts +5 -0
- package/src/data/ticker-store.ts +15 -0
- package/src/docs/content.ts +215 -0
- package/src/docs/load.ts +139 -0
- package/src/docs/requests.ts +39 -0
- package/src/docs/snapshot.chunk.ts +8 -0
- package/src/docs/snapshot.json +7416 -0
- package/src/docs/topics.ts +216 -0
- package/src/i18n/es.ts +61 -4
- package/src/i18n/ja.ts +61 -4
- package/src/i18n/ko.ts +61 -4
- package/src/i18n/zh-cn.ts +61 -4
- package/src/i18n/zh-tw.ts +61 -4
- package/src/layout/desks.ts +1 -1
- package/src/layout/pane-manager/dock-tree.ts +18 -0
- package/src/layout/pane-manager/index.ts +1 -0
- package/src/market-data/coordinator/chart.ts +10 -4
- package/src/market-data/coordinator/index.ts +6 -3
- package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
- package/src/market-data/futures-contract.ts +151 -0
- package/src/market-data/hooks.tsx +10 -2
- package/src/market-data/market/format.ts +39 -21
- package/src/market-data/market/freshness.ts +81 -18
- package/src/market-data/market/status.ts +19 -23
- package/src/market-data/published-apac-sessions.ts +23 -1
- package/src/market-data/quotes/contributions.ts +3 -0
- package/src/market-data/quotes/metadata.ts +7 -24
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +5 -4
- package/src/market-data/result-types.ts +2 -0
- package/src/plugins/builtin/account-management/model.ts +1 -56
- package/src/plugins/builtin/account-management/pane.tsx +6 -4
- package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
- package/src/plugins/builtin/alerts/cli.ts +313 -47
- package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
- package/src/plugins/builtin/alerts/events.ts +23 -2
- package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +41 -9
- package/src/plugins/builtin/alerts/pane.tsx +8 -0
- package/src/plugins/builtin/alerts/research-builder.ts +8 -3
- package/src/plugins/builtin/alerts/research-rules.ts +18 -2
- package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
- package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
- package/src/plugins/builtin/alerts/scheduled.ts +254 -0
- package/src/plugins/builtin/alerts/targets.ts +92 -0
- package/src/plugins/builtin/analytics/index.tsx +4 -2
- package/src/plugins/builtin/analytics/risk-headless.ts +30 -12
- package/src/plugins/builtin/analytics/risk-math.ts +91 -27
- package/src/plugins/builtin/analytics/risk-model.ts +35 -5
- package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
- package/src/plugins/builtin/attention/index.tsx +2 -0
- package/src/plugins/builtin/attention/pane.tsx +3 -1
- package/src/plugins/builtin/attention/series.ts +26 -0
- package/src/plugins/builtin/awards/index.tsx +2 -0
- package/src/plugins/builtin/awards/pane.tsx +3 -1
- package/src/plugins/builtin/awards/series.ts +29 -0
- package/src/plugins/builtin/bond-calculator/model.ts +2 -1
- package/src/plugins/builtin/catalysts/pane.tsx +3 -1
- package/src/plugins/builtin/cds/client.ts +70 -13
- package/src/plugins/builtin/cds/headless.ts +116 -19
- package/src/plugins/builtin/cds/index.tsx +3 -1
- package/src/plugins/builtin/cds/model.ts +193 -31
- package/src/plugins/builtin/cds/pane.tsx +56 -14
- package/src/plugins/builtin/cds/series.ts +19 -0
- package/src/plugins/builtin/central-bank-rates/index.tsx +2 -0
- package/src/plugins/builtin/central-bank-rates/series.ts +42 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +192 -255
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
- package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
- package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
- package/src/plugins/builtin/chart-composer/headless.ts +8 -3
- package/src/plugins/builtin/chart-composer/index.tsx +9 -2
- package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
- package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
- package/src/plugins/builtin/chat/controller/index.ts +2 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
- package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
- package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
- package/src/plugins/builtin/cloud/askg/model.ts +27 -8
- package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
- package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
- package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
- package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
- package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
- package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
- package/src/plugins/builtin/company-attention/headless.ts +19 -5
- package/src/plugins/builtin/company-attention/index.tsx +2 -0
- package/src/plugins/builtin/company-attention/model.ts +26 -7
- package/src/plugins/builtin/company-attention/pane.tsx +12 -9
- package/src/plugins/builtin/company-attention/series.ts +52 -0
- package/src/plugins/builtin/company-kpis/pane.tsx +4 -2
- package/src/plugins/builtin/composite-plugins.ts +19 -13
- package/src/plugins/builtin/cot/index.tsx +3 -1
- package/src/plugins/builtin/cot/model.ts +40 -11
- package/src/plugins/builtin/cot/series.ts +27 -0
- package/src/plugins/builtin/credit-boards/index.tsx +2 -0
- package/src/plugins/builtin/credit-boards/series.ts +66 -0
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -0
- package/src/plugins/builtin/credit-conditions/series.ts +26 -0
- package/src/plugins/builtin/credit-documents/headless.ts +31 -1
- package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
- package/src/plugins/builtin/crypto-board/headless.ts +2 -3
- package/src/plugins/builtin/crypto-board/index.tsx +2 -0
- package/src/plugins/builtin/crypto-board/model.ts +12 -0
- package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
- package/src/plugins/builtin/crypto-board/series.ts +48 -0
- package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
- package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/series.ts +45 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +2 -2
- package/src/plugins/builtin/dividend-yield/index.tsx +2 -0
- package/src/plugins/builtin/dividend-yield/series.ts +20 -0
- package/src/plugins/builtin/docs/blocks.tsx +181 -0
- package/src/plugins/builtin/docs/index.tsx +68 -0
- package/src/plugins/builtin/docs/pane.tsx +426 -0
- package/src/plugins/builtin/docs/targets.ts +72 -0
- package/src/plugins/builtin/docs/use-docs.ts +60 -0
- package/src/plugins/builtin/doe/index.tsx +2 -0
- package/src/plugins/builtin/doe/series.ts +62 -0
- package/src/plugins/builtin/earnings/client.ts +3 -2
- package/src/plugins/builtin/earnings/format.ts +1 -5
- package/src/plugins/builtin/earnings/headless.ts +58 -6
- package/src/plugins/builtin/earnings/history-model.ts +15 -1
- package/src/plugins/builtin/earnings/history-table.ts +13 -2
- package/src/plugins/builtin/earnings/history.tsx +7 -3
- package/src/plugins/builtin/econ/fred-catalog.ts +189 -0
- package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
- package/src/plugins/builtin/econ/index.tsx +2 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
- package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
- package/src/plugins/builtin/exposure/holdings.ts +1 -1
- package/src/plugins/builtin/exposure/pane.tsx +3 -1
- package/src/plugins/builtin/fear-greed/index.tsx +4 -0
- package/src/plugins/builtin/fear-greed/series.ts +52 -0
- package/src/plugins/builtin/futures/index.tsx +43 -3
- package/src/plugins/builtin/futures/model.ts +1 -1
- package/src/plugins/builtin/futures/returns.ts +1 -1
- package/src/plugins/builtin/futures/series.ts +13 -0
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +70 -9
- package/src/plugins/builtin/futures-curve/index.tsx +1 -1
- package/src/plugins/builtin/futures-curve/model.ts +66 -11
- package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
- package/src/plugins/builtin/fx-matrix/index.tsx +1 -1
- package/src/plugins/builtin/gpu/board.tsx +13 -10
- package/src/plugins/builtin/gpu/changes.tsx +4 -4
- package/src/plugins/builtin/gpu/client.ts +19 -1
- package/src/plugins/builtin/gpu/equities.tsx +14 -10
- package/src/plugins/builtin/gpu/headless.ts +56 -25
- package/src/plugins/builtin/gpu/history.tsx +3 -3
- package/src/plugins/builtin/gpu/index.tsx +2 -0
- package/src/plugins/builtin/gpu/model.ts +101 -16
- package/src/plugins/builtin/gpu/pane.tsx +28 -12
- package/src/plugins/builtin/gpu/series.ts +38 -0
- package/src/plugins/builtin/help/function-card.tsx +25 -6
- package/src/plugins/builtin/help/index.tsx +17 -8
- package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
- package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
- package/src/plugins/builtin/holders/client.ts +22 -3
- package/src/plugins/builtin/holders/format.ts +18 -3
- package/src/plugins/builtin/holders/headless.ts +36 -133
- package/src/plugins/builtin/holders/pane.tsx +11 -4
- package/src/plugins/builtin/holders/report-header.ts +40 -5
- package/src/plugins/builtin/holders/report-rows.ts +240 -0
- package/src/plugins/builtin/insider/client.ts +35 -20
- package/src/plugins/builtin/insider/headless.ts +41 -11
- package/src/plugins/builtin/insider/index.tsx +26 -9
- package/src/plugins/builtin/insider/insider-data.ts +10 -0
- package/src/plugins/builtin/insider/issuer.ts +49 -0
- package/src/plugins/builtin/insider/model.ts +3 -0
- package/src/plugins/builtin/iv-history/client.ts +14 -4
- package/src/plugins/builtin/iv-history/headless.ts +7 -4
- package/src/plugins/builtin/iv-history/index.tsx +2 -0
- package/src/plugins/builtin/iv-history/model.ts +111 -7
- package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
- package/src/plugins/builtin/iv-history/series.ts +29 -0
- package/src/plugins/builtin/jobs/headless.ts +28 -3
- package/src/plugins/builtin/jobs/index.tsx +3 -1
- package/src/plugins/builtin/jobs/series.ts +19 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
- package/src/plugins/builtin/macro-day/client.ts +44 -3
- package/src/plugins/builtin/macro-day/headless.ts +13 -10
- package/src/plugins/builtin/macro-day/model.ts +56 -10
- package/src/plugins/builtin/macro-day/pane.tsx +30 -20
- package/src/plugins/builtin/market-heatmap/model.ts +19 -11
- package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
- package/src/plugins/builtin/market-movers/client.ts +7 -5
- package/src/plugins/builtin/market-movers/index.tsx +3 -2
- package/src/plugins/builtin/market-movers/model.ts +30 -0
- package/src/plugins/builtin/market-movers/screener.ts +31 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
- package/src/plugins/builtin/market-valuation/index.tsx +3 -3
- package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
- package/src/plugins/builtin/members/headless.ts +7 -2
- package/src/plugins/builtin/members/model.ts +31 -3
- package/src/plugins/builtin/members/pane.tsx +3 -6
- package/src/plugins/builtin/mna/headless.ts +15 -3
- package/src/plugins/builtin/money-markets/index.tsx +2 -0
- package/src/plugins/builtin/money-markets/series.ts +41 -0
- package/src/plugins/builtin/notes/cli.ts +12 -7
- package/src/plugins/builtin/options/view.tsx +1 -1
- package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
- package/src/plugins/builtin/options-positioning/client.ts +7 -3
- package/src/plugins/builtin/options-positioning/headless.ts +1 -0
- package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +2 -1
- package/src/plugins/builtin/options-scenario/headless.ts +1 -0
- package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
- package/src/plugins/builtin/perps/client.ts +40 -6
- package/src/plugins/builtin/perps/equity-row.tsx +33 -11
- package/src/plugins/builtin/perps/freshness.ts +66 -0
- package/src/plugins/builtin/perps/headless.ts +45 -30
- package/src/plugins/builtin/perps/index.tsx +18 -1
- package/src/plugins/builtin/perps/model.ts +20 -5
- package/src/plugins/builtin/perps/pane.tsx +76 -20
- package/src/plugins/builtin/perps/series.ts +76 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +67 -61
- package/src/plugins/builtin/plugin-module.ts +3 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +273 -0
- package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +331 -65
- package/src/plugins/builtin/portfolio-list/cli/render.ts +200 -31
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +24 -0
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -47
- package/src/plugins/builtin/portfolio-list/column-values.ts +1 -1
- package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +34 -4
- package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -1
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +17 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +1 -1
- package/src/plugins/builtin/portfolio-list/table.tsx +7 -1
- package/src/plugins/builtin/power/client.ts +16 -0
- package/src/plugins/builtin/power/evidence.ts +6 -2
- package/src/plugins/builtin/power/headless.ts +71 -7
- package/src/plugins/builtin/power/index.tsx +4 -1
- package/src/plugins/builtin/power/model.ts +72 -1
- package/src/plugins/builtin/power/pane.tsx +32 -9
- package/src/plugins/builtin/rate-path/headless.ts +11 -3
- package/src/plugins/builtin/realized-vol/headless.ts +5 -0
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
- package/src/plugins/builtin/research/event-model.ts +68 -24
- package/src/plugins/builtin/research/events-headless.ts +2 -1
- package/src/plugins/builtin/research/headless.ts +2 -1
- package/src/plugins/builtin/seasonality/client.ts +15 -7
- package/src/plugins/builtin/seasonality/headless.ts +36 -12
- package/src/plugins/builtin/seasonality/index.tsx +2 -2
- package/src/plugins/builtin/seasonality/model.ts +119 -0
- package/src/plugins/builtin/seasonality/pane.tsx +108 -37
- package/src/plugins/builtin/series-inventory.ts +91 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
- package/src/plugins/builtin/shared/command-tab.ts +30 -12
- package/src/plugins/builtin/shared/earnings-report.ts +55 -0
- package/src/plugins/builtin/shared/fred-points.ts +20 -0
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
- package/src/plugins/builtin/shared/open-description.ts +29 -0
- package/src/plugins/builtin/shared/report-freshness.ts +9 -0
- package/src/plugins/builtin/shared/series-warning.ts +5 -0
- package/src/plugins/builtin/short-interest/headless.ts +1 -0
- package/src/plugins/builtin/short-interest/index.tsx +2 -0
- package/src/plugins/builtin/short-interest/series.ts +36 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/short-volume/index.tsx +2 -0
- package/src/plugins/builtin/short-volume/series.ts +23 -0
- package/src/plugins/builtin/social-mentions/index.tsx +2 -0
- package/src/plugins/builtin/social-mentions/series.ts +23 -0
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +3 -1
- package/src/plugins/builtin/thirteenf/api.ts +1 -0
- package/src/plugins/builtin/thirteenf/data.ts +6 -4
- package/src/plugins/builtin/thirteenf/headless.ts +217 -36
- package/src/plugins/builtin/thirteenf/model.ts +39 -1
- package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
- package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
- package/src/plugins/builtin/thirteenf/types.ts +2 -0
- package/src/plugins/builtin/ticker-detail/index.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +48 -4
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
- package/src/plugins/builtin/time-sales/headless.ts +1 -0
- package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
- package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
- package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
- package/src/plugins/builtin/vol-surface/headless.ts +1 -0
- package/src/plugins/builtin/volatility/index.tsx +2 -0
- package/src/plugins/builtin/volatility/series.ts +84 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
- package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
- package/src/plugins/builtin/world-venue-map/index.ts +2 -1
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +8 -4
- package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
- package/src/plugins/builtin/yield-curve/chart.ts +2 -2
- package/src/plugins/builtin/yield-curve/curves.ts +21 -8
- package/src/plugins/builtin/yield-curve/headless.ts +71 -18
- package/src/plugins/builtin/yield-curve/index.tsx +3 -1
- package/src/plugins/builtin/yield-curve/series.ts +86 -0
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/registry/index.ts +89 -4
- package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
- package/src/portfolio/position-value.ts +40 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
- package/src/public/time-series.ts +17 -0
- package/src/react/auto-refresh.ts +13 -3
- package/src/remote/app-host.tsx +20 -4
- package/src/remote/confirm-change.tsx +85 -0
- package/src/remote/controller-utils.ts +8 -1
- package/src/remote/controller.ts +123 -6
- package/src/remote/pane-screenshot.ts +47 -0
- package/src/remote/schema.ts +62 -0
- package/src/remote/types.ts +30 -0
- package/src/remote/watchlist.ts +306 -0
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/dom/data-table/frozen-column.ts +3 -1
- package/src/renderers/dom/data-table/index.tsx +33 -6
- package/src/renderers/dom/data-table/row.tsx +27 -1
- package/src/renderers/dom/desktop/control-styles.ts +63 -1
- package/src/renderers/dom/desktop/controls.tsx +30 -23
- package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
- package/src/renderers/dom/desktop/icons.tsx +7 -0
- package/src/renderers/dom/dom-ui-host.tsx +3 -0
- package/src/renderers/dom/host/box.tsx +3 -0
- package/src/renderers/dom/host/chart-surface.tsx +6 -2
- package/src/renderers/dom/host/live-frame.ts +6 -2
- package/src/renderers/dom/host/overflow-fade.ts +14 -1
- package/src/renderers/dom/host/size-observer.ts +26 -0
- package/src/renderers/dom/host/surface-3d.tsx +7 -2
- package/src/renderers/dom/host/text.tsx +1 -1
- package/src/renderers/dom/styles.css +61 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +17 -2
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +19 -11
- package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
- package/src/renderers/electrobun/view/main.tsx +2 -0
- package/src/series/capability.ts +75 -0
- package/src/series/csv.ts +160 -0
- package/src/series/files.ts +107 -0
- package/src/series/registry.ts +198 -0
- package/src/series/resolve.ts +107 -0
- package/src/series/standalone.ts +48 -0
- package/src/series/types.ts +145 -0
- package/src/series/validate.ts +171 -0
- package/src/sources/gloomberb-cloud/index.ts +7 -7
- package/src/sources/gloomberb-cloud/normalizers.ts +1 -0
- package/src/sources/history-result.ts +1 -0
- package/src/sources/listing-symbols.ts +4 -1
- package/src/sources/provider-router/batches.ts +4 -1
- package/src/sources/provider-router/cache.ts +4 -2
- package/src/sources/provider-router/cached-routes.ts +1 -1
- package/src/sources/provider-router/financial-routes.ts +1 -0
- package/src/sources/provider-router/financials.ts +13 -0
- package/src/sources/provider-router/history.ts +43 -25
- package/src/sources/provider-router/search.ts +1 -0
- package/src/sync/core-contributors.ts +1 -0
- package/src/tickers/company-name.ts +75 -0
- package/src/tickers/instrument-kind.ts +25 -0
- package/src/tickers/open-target.ts +3 -2
- package/src/tickers/search/index.ts +45 -7
- package/src/tickers/search/ranking.ts +33 -17
- package/src/tickers/search/types.ts +7 -1
- package/src/tickers/us-listing.ts +34 -0
- package/src/time-series/hooks.ts +9 -0
- package/src/time-series/resolve.ts +95 -16
- package/src/time-series/types.ts +4 -2
- package/src/time-series/use-chart-resolution.ts +32 -0
- package/src/types/config.ts +6 -0
- package/src/types/data-provider.ts +5 -0
- package/src/types/financials.ts +52 -1
- package/src/types/headless.ts +61 -0
- package/src/types/plugin.ts +19 -0
- package/src/types/price-history.ts +7 -0
- package/src/types/ticker.ts +14 -0
- package/src/ui/host.tsx +18 -0
- package/src/ui/live-resize.ts +81 -0
- package/src/ui/live-stretch.ts +121 -0
- package/src/ui/measured-cells.ts +58 -0
- package/src/ui/pane-fill.ts +11 -0
- package/src/utils/basis-points.ts +17 -0
- package/src/utils/cli-output.ts +7 -1
- package/src/utils/concurrency.ts +25 -0
- package/src/utils/crypto-pair.ts +20 -0
- package/src/utils/currency-pair.ts +19 -0
- package/src/utils/decimal-comma.ts +19 -0
- package/src/utils/dom-screenshot-css.ts +265 -0
- package/src/utils/dom-screenshot-rasters.ts +276 -0
- package/src/utils/dom-screenshot.ts +437 -52
- package/src/utils/exchange-rate-snapshot.ts +6 -2
- package/src/utils/exchanges.ts +107 -1
- package/src/utils/format.ts +16 -3
- package/src/utils/fundamentals.ts +66 -0
- package/src/utils/futures-generic.ts +6 -12
- package/src/utils/fx-market-hours.ts +15 -5
- package/src/utils/price-history.ts +99 -42
- package/src/utils/sec-eps-basis.ts +24 -11
- package/src/utils/sec.ts +61 -7
- package/src/utils/utc-time.ts +51 -4
- package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
- /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "../../../components";
|
|
13
13
|
import type { PaneProps } from "../../../types/plugin";
|
|
14
14
|
import { colors } from "../../../theme/colors";
|
|
15
|
-
import {
|
|
15
|
+
import { nextHeaderSort, type SortDirection } from "../../../utils/sort-values";
|
|
16
16
|
import { isPlainArrowUp, stopSearchFocusNavigation } from "../../../utils/search-focus-navigation";
|
|
17
17
|
import { usePaneSettingValue } from "../../../state/app/context";
|
|
18
18
|
import { usePluginAppActions, usePluginPaneState } from "../../runtime";
|
|
@@ -20,22 +20,28 @@ import { usePaneStatusLinkFooter } from "../../../components/layout/pane/status-
|
|
|
20
20
|
import { PaneTemplateInputStep } from "../../../components/pane-template-wizard";
|
|
21
21
|
import { type PromptContext, useDialog } from "../../../ui/dialog";
|
|
22
22
|
import {
|
|
23
|
-
CATALOG_FILTERS,
|
|
24
23
|
CHART_COMPOSER_TEMPLATE_ID,
|
|
25
24
|
DATA_CATALOG_PANE_ID,
|
|
26
25
|
catalogEmptyCopy,
|
|
27
26
|
catalogExpressionForRow,
|
|
28
27
|
catalogInstrumentMatchesQuery,
|
|
28
|
+
catalogRowsForListedCrypto,
|
|
29
29
|
catalogRowsForResolvedInstruments,
|
|
30
|
+
catalogRowsFromEntries,
|
|
31
|
+
catalogTabs,
|
|
32
|
+
compareCatalogGroups,
|
|
33
|
+
compareCatalogText,
|
|
30
34
|
filterCatalogRows,
|
|
31
|
-
|
|
35
|
+
frequencyRank,
|
|
32
36
|
looksLikeCatalogTickerQuery,
|
|
37
|
+
mergeCatalogRows,
|
|
38
|
+
normalizeCatalogFilter,
|
|
33
39
|
type CatalogFilterId,
|
|
34
40
|
type CatalogSeriesRow,
|
|
35
41
|
} from "./catalog-inventory";
|
|
36
|
-
import { useCatalogUniverse } from "./use-series-catalog";
|
|
42
|
+
import { useCatalogUniverse, useRegisteredSeries } from "./use-series-catalog";
|
|
37
43
|
|
|
38
|
-
type CatalogColumnId = "series" | "
|
|
44
|
+
type CatalogColumnId = "series" | "group" | "unit" | "frequency" | "publisher" | "expression";
|
|
39
45
|
type CatalogColumn = DataTableColumn & { id: CatalogColumnId };
|
|
40
46
|
|
|
41
47
|
interface CatalogSortPreference {
|
|
@@ -43,32 +49,59 @@ interface CatalogSortPreference {
|
|
|
43
49
|
direction: SortDirection;
|
|
44
50
|
}
|
|
45
51
|
|
|
46
|
-
const DEFAULT_SORT: CatalogSortPreference = { columnId: "
|
|
52
|
+
const DEFAULT_SORT: CatalogSortPreference = { columnId: "group", direction: "asc" };
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
const FREQUENCY_LABELS: Record<CatalogSeriesRow["frequency"], string> = {
|
|
55
|
+
intraday: "Intraday",
|
|
56
|
+
daily: "Daily",
|
|
57
|
+
weekly: "Weekly",
|
|
58
|
+
monthly: "Monthly",
|
|
59
|
+
quarterly: "Quarterly",
|
|
60
|
+
annual: "Annual",
|
|
61
|
+
irregular: "Irregular",
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function compareRows(columnId: CatalogColumnId, left: CatalogSeriesRow, right: CatalogSeriesRow): number {
|
|
49
65
|
switch (columnId) {
|
|
50
66
|
case "series":
|
|
51
|
-
return
|
|
67
|
+
return compareCatalogText(left.label, right.label);
|
|
68
|
+
case "group":
|
|
69
|
+
return compareCatalogGroups(left.group, right.group);
|
|
70
|
+
case "unit":
|
|
71
|
+
return compareCatalogText(left.unit, right.unit);
|
|
72
|
+
case "frequency":
|
|
73
|
+
return frequencyRank(left.frequency) - frequencyRank(right.frequency);
|
|
52
74
|
case "publisher":
|
|
53
|
-
// Blank publishers (market data) sort after the named ones.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return row.kind;
|
|
75
|
+
// Blank publishers (market data) sort after the named ones, either way.
|
|
76
|
+
if (!left.publisher || !right.publisher) return 0;
|
|
77
|
+
return compareCatalogText(left.publisher, right.publisher);
|
|
57
78
|
case "expression":
|
|
58
|
-
return
|
|
79
|
+
return compareCatalogText(left.expression, right.expression);
|
|
59
80
|
}
|
|
60
81
|
}
|
|
61
82
|
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
return [
|
|
83
|
+
function sortRows(rows: CatalogSeriesRow[], { columnId, direction }: CatalogSortPreference): CatalogSeriesRow[] {
|
|
84
|
+
// Rows arrive in the default order, so the default sort is free.
|
|
85
|
+
if (columnId === DEFAULT_SORT.columnId && direction === DEFAULT_SORT.direction) return rows;
|
|
86
|
+
const sign = direction === "asc" ? 1 : -1;
|
|
87
|
+
return [...rows].sort((left, right) => {
|
|
88
|
+
if (columnId === "publisher" && !left.publisher !== !right.publisher) return left.publisher ? -1 : 1;
|
|
89
|
+
return sign * compareRows(columnId, left, right) || left.order - right.order;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** The table keeps the series name and its expression; the rest fold away as the pane narrows. */
|
|
94
|
+
function buildColumns(width: number, showGroup: boolean): CatalogColumn[] {
|
|
95
|
+
const expressionWidth = Math.min(30, Math.max(16, Math.floor(width * 0.26)));
|
|
96
|
+
const columns: CatalogColumn[] = [
|
|
67
97
|
{ id: "series", label: "SERIES", width: 18, flexGrow: 1, align: "left" },
|
|
68
|
-
{ id: "publisher", label: "PUBLISHER", width: publisherWidth, align: "left" },
|
|
69
|
-
{ id: "kind", label: "KIND", width: kindWidth, align: "left" },
|
|
70
|
-
{ id: "expression", label: "EXPRESSION", width: expressionWidth, align: "left" },
|
|
71
98
|
];
|
|
99
|
+
if (showGroup && width >= 70) columns.push({ id: "group", label: "KIND", width: 12, align: "left" });
|
|
100
|
+
if (width >= 84) columns.push({ id: "unit", label: "UNIT", width: 10, align: "left" });
|
|
101
|
+
if (width >= 96) columns.push({ id: "frequency", label: "FREQ", width: 9, align: "left" });
|
|
102
|
+
if (width >= 60) columns.push({ id: "publisher", label: "PUBLISHER", width: 10, align: "left" });
|
|
103
|
+
columns.push({ id: "expression", label: "EXPRESSION", width: expressionWidth, align: "left" });
|
|
104
|
+
return columns;
|
|
72
105
|
}
|
|
73
106
|
|
|
74
107
|
export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
@@ -76,11 +109,14 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
76
109
|
const dialog = useDialog();
|
|
77
110
|
const [seedQuery] = usePaneSettingValue("query", "");
|
|
78
111
|
const [searchQuery, setSearchQuery] = useState(seedQuery);
|
|
79
|
-
const [
|
|
112
|
+
const [savedFilter, setFilter] = usePluginPaneState<CatalogFilterId>("activeTab", "all");
|
|
80
113
|
const [selectedId, setSelectedId] = usePluginPaneState<string | null>("selectedId", null);
|
|
81
114
|
const [sortPreference, setSortPreference] = useState<CatalogSortPreference>(DEFAULT_SORT);
|
|
82
115
|
const { active: searchFocused, focus: focusSearch, searchProps } = useQueryBarSearch();
|
|
83
116
|
|
|
117
|
+
const entries = useRegisteredSeries();
|
|
118
|
+
const catalogRows = useMemo(() => catalogRowsFromEntries(entries), [entries]);
|
|
119
|
+
const filter = normalizeCatalogFilter(savedFilter, catalogRows);
|
|
84
120
|
const tickerQuery = looksLikeCatalogTickerQuery(searchQuery);
|
|
85
121
|
const { instruments, loading: universeLoading } = useCatalogUniverse(
|
|
86
122
|
tickerQuery ? searchQuery : "",
|
|
@@ -88,25 +124,20 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
88
124
|
const loading = tickerQuery && universeLoading;
|
|
89
125
|
const emptyCopy = catalogEmptyCopy(loading, searchQuery);
|
|
90
126
|
|
|
127
|
+
const listedCrypto = useMemo(
|
|
128
|
+
() => catalogRowsForListedCrypto(catalogRows, instruments),
|
|
129
|
+
[catalogRows, instruments],
|
|
130
|
+
);
|
|
91
131
|
const rows = useMemo(() => {
|
|
92
|
-
const staticRows = listStaticCatalogInventory(instruments);
|
|
93
132
|
const resolvedRows = tickerQuery
|
|
94
133
|
? catalogRowsForResolvedInstruments(
|
|
134
|
+
catalogRows,
|
|
95
135
|
instruments.filter((instrument) => catalogInstrumentMatchesQuery(instrument, searchQuery)),
|
|
96
136
|
)
|
|
97
137
|
: [];
|
|
98
|
-
const merged =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
const filtered = filterCatalogRows([...merged.values()], filter, searchQuery);
|
|
103
|
-
const direction = sortPreference.direction;
|
|
104
|
-
const columnId = sortPreference.columnId;
|
|
105
|
-
return [...filtered].sort((left, right) => (
|
|
106
|
-
compareSortValues(sortValue(columnId, left), sortValue(columnId, right), direction)
|
|
107
|
-
|| left.label.localeCompare(right.label)
|
|
108
|
-
));
|
|
109
|
-
}, [filter, instruments, searchQuery, sortPreference, tickerQuery]);
|
|
138
|
+
const merged = mergeCatalogRows(catalogRows, [...resolvedRows, ...listedCrypto]);
|
|
139
|
+
return sortRows(filterCatalogRows(merged, filter, searchQuery), sortPreference);
|
|
140
|
+
}, [catalogRows, filter, instruments, listedCrypto, searchQuery, sortPreference, tickerQuery]);
|
|
110
141
|
|
|
111
142
|
useEffect(() => {
|
|
112
143
|
if (selectedId && rows.some((row) => row.id === selectedId)) return;
|
|
@@ -119,12 +150,13 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
119
150
|
);
|
|
120
151
|
const selectedUrl = selectedRow?.url ?? null;
|
|
121
152
|
|
|
122
|
-
const columns = useMemo(() => buildColumns(width), [width]);
|
|
153
|
+
const columns = useMemo(() => buildColumns(width, filter === "all"), [filter, width]);
|
|
123
154
|
|
|
124
155
|
const chartSelected = useCallback(async (row: CatalogSeriesRow | null) => {
|
|
125
156
|
if (!row) return;
|
|
126
|
-
if (row.
|
|
127
|
-
const option = row.
|
|
157
|
+
if (row.input) {
|
|
158
|
+
const option = row.input === "option";
|
|
159
|
+
const crypto = row.input === "crypto";
|
|
128
160
|
const ticker = await dialog.prompt<string>({
|
|
129
161
|
closeOnClickOutside: true,
|
|
130
162
|
content: (context: PromptContext<string>) => (
|
|
@@ -133,11 +165,13 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
133
165
|
step={{
|
|
134
166
|
key: "ticker",
|
|
135
167
|
label: `Chart ${row.label}`,
|
|
136
|
-
placeholder: option ? "AAPL 260618C00200000" : "AAPL",
|
|
168
|
+
placeholder: option ? "AAPL 260618C00200000" : crypto ? "BTC-USD" : "AAPL",
|
|
137
169
|
type: "text",
|
|
138
170
|
body: [option
|
|
139
171
|
? `Enter an option symbol to chart ${row.label}.`
|
|
140
|
-
:
|
|
172
|
+
: crypto
|
|
173
|
+
? `Enter a crypto pair to chart ${row.label}.`
|
|
174
|
+
: `Enter a ticker to chart ${row.label}.`],
|
|
141
175
|
}}
|
|
142
176
|
/>
|
|
143
177
|
),
|
|
@@ -147,7 +181,7 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
147
181
|
createPaneFromTemplate(CHART_COMPOSER_TEMPLATE_ID, { arg: expression });
|
|
148
182
|
return;
|
|
149
183
|
}
|
|
150
|
-
createPaneFromTemplate(CHART_COMPOSER_TEMPLATE_ID, { arg: row.
|
|
184
|
+
createPaneFromTemplate(CHART_COMPOSER_TEMPLATE_ID, { arg: row.template });
|
|
151
185
|
}, [createPaneFromTemplate, dialog]);
|
|
152
186
|
|
|
153
187
|
// `/` and `g` are footer hints, which bind their own keys; the table only
|
|
@@ -171,10 +205,14 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
171
205
|
switch (column.id) {
|
|
172
206
|
case "series":
|
|
173
207
|
return { text: row.label, color: colors.textBright };
|
|
208
|
+
case "group":
|
|
209
|
+
return { text: row.group, color: colors.textDim };
|
|
210
|
+
case "unit":
|
|
211
|
+
return { text: row.unit, color: colors.textDim };
|
|
212
|
+
case "frequency":
|
|
213
|
+
return { text: FREQUENCY_LABELS[row.frequency], color: colors.textDim };
|
|
174
214
|
case "publisher":
|
|
175
215
|
return { text: row.publisher, color: colors.textMuted };
|
|
176
|
-
case "kind":
|
|
177
|
-
return { text: row.kind, color: colors.textDim };
|
|
178
216
|
case "expression":
|
|
179
217
|
return { text: row.expression, color: colors.text };
|
|
180
218
|
}
|
|
@@ -195,10 +233,10 @@ export function DataCatalogPane({ focused, width, height }: PaneProps) {
|
|
|
195
233
|
});
|
|
196
234
|
|
|
197
235
|
const tabs = useMemo(
|
|
198
|
-
() =>
|
|
199
|
-
[],
|
|
236
|
+
() => catalogTabs(catalogRows).map((entry) => ({ label: entry.label, value: entry.id })),
|
|
237
|
+
[catalogRows],
|
|
200
238
|
);
|
|
201
|
-
const selectFilter = useCallback((value: string) => setFilter(value
|
|
239
|
+
const selectFilter = useCallback((value: string) => setFilter(value), [setFilter]);
|
|
202
240
|
const { strip: tabStrip } = usePaneTabs({
|
|
203
241
|
tabs,
|
|
204
242
|
activeValue: filter,
|
|
@@ -78,14 +78,15 @@ export function SeriesEditorDialog({ dialogId, resolve, initialSpec }: SeriesEdi
|
|
|
78
78
|
while (navigationKeys.length > 0 && [...navigationKeys, ...seriesKeys].join(" · ").length > tuiContentWidth) {
|
|
79
79
|
navigationKeys.pop();
|
|
80
80
|
}
|
|
81
|
-
const footer = isDesktop
|
|
82
|
-
? seriesKeys.join(" · ") || undefined
|
|
83
|
-
: [...navigationKeys, ...seriesKeys].join(" · ");
|
|
84
81
|
|
|
85
82
|
return (
|
|
86
83
|
<DialogFrame
|
|
87
84
|
title="Chart Series"
|
|
88
|
-
footer={
|
|
85
|
+
footer={[...navigationKeys, ...seriesKeys].join(" · ")}
|
|
86
|
+
// The desktop's fields take the pointer and arrows like any form.
|
|
87
|
+
desktopFooter={selected
|
|
88
|
+
? { keys: [{ key: "E", label: "source" }, { key: "P", label: "panel" }, { key: "L", label: "log scale" }] }
|
|
89
|
+
: null}
|
|
89
90
|
>
|
|
90
91
|
<Box
|
|
91
92
|
flexDirection="column"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isMarketFieldId, listTimeSeriesFields } from "../../../time-series/field-catalog";
|
|
2
|
+
import type { SeriesPeriod, TimeSeriesFieldDefinition } from "../../../time-series/types";
|
|
3
|
+
import type { SeriesDefinition, SeriesFrequency } from "../../../series/types";
|
|
4
|
+
import { fieldCategory } from "./series-catalog";
|
|
5
|
+
|
|
6
|
+
/** The short name an expression uses for a field: `price` for OHLCV, else the id's last part. */
|
|
7
|
+
function chartFieldToken(fieldId: string): string {
|
|
8
|
+
if (fieldId === "market.ohlcv") return "price";
|
|
9
|
+
return fieldId.split(".").at(-1) ?? fieldId;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function fieldFrequency(period: SeriesPeriod): SeriesFrequency {
|
|
13
|
+
if (period === "auto") return "daily";
|
|
14
|
+
return period === "ttm" ? "quarterly" : period;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function fieldSeries(field: TimeSeriesFieldDefinition, input: "ticker" | "option"): SeriesDefinition {
|
|
18
|
+
return {
|
|
19
|
+
id: `${input === "option" ? "option" : "field"}:${field.id}`,
|
|
20
|
+
name: field.label,
|
|
21
|
+
unit: field.unit,
|
|
22
|
+
frequency: fieldFrequency(field.nativeFrequency),
|
|
23
|
+
group: input === "option" ? "Options" : "Securities",
|
|
24
|
+
tags: [fieldCategory(field), field.shortLabel, ...(input === "option" ? ["option"] : [])],
|
|
25
|
+
input,
|
|
26
|
+
expression: `{ticker}:${chartFieldToken(field.id)}`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Every ticker field once, asking for the ticker when charted, and the market
|
|
32
|
+
* fields again for option contracts. Typing a ticker in the catalog fills them in.
|
|
33
|
+
*/
|
|
34
|
+
export function listFieldSeries(): SeriesDefinition[] {
|
|
35
|
+
const fields = listTimeSeriesFields();
|
|
36
|
+
return [
|
|
37
|
+
...fields.map((field) => fieldSeries(field, "ticker")),
|
|
38
|
+
...fields.filter((field) => isMarketFieldId(field.id)).map((field) => fieldSeries(field, "option")),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
@@ -212,11 +212,16 @@ export async function loadChartPaneModel(
|
|
|
212
212
|
/**
|
|
213
213
|
* Price series are bar histories, stale once bars of the coarsest size stop
|
|
214
214
|
* arriving; fundamentals, valuations and economic series are reported data.
|
|
215
|
+
* A chart of capability series alone (CHOKE's vessel transits) is a dataset,
|
|
216
|
+
* dated by its newest observation and how far behind that is.
|
|
215
217
|
*/
|
|
216
|
-
function chartFreshness(series: readonly HeadlessSeries[]): HeadlessPaneFreshness {
|
|
218
|
+
function chartFreshness(series: readonly HeadlessSeries[], spec: ChartSpec): HeadlessPaneFreshness {
|
|
217
219
|
const order = ["1wk", "1mo"];
|
|
218
220
|
const resolutions = series.map((entry) => (entry as HeadlessSeries & { historyResolution?: string }).historyResolution);
|
|
219
|
-
|
|
221
|
+
const dataset = spec.series.length > 0 && spec.series.every(({ source }) => source.kind === "capability");
|
|
222
|
+
if (!series.length || resolutions.some((resolution) => !resolution)) {
|
|
223
|
+
return { ...REPORTED_DATA, basis: "reported and published data", ...(dataset ? { dataset } : {}) };
|
|
224
|
+
}
|
|
220
225
|
const coarsest = resolutions.reduce((worst, resolution) => (
|
|
221
226
|
order.indexOf(resolution!) > order.indexOf(worst!) ? resolution : worst
|
|
222
227
|
), resolutions[0]);
|
|
@@ -296,7 +301,7 @@ export function chartHeadless(template: keyof typeof paneSchemas): HeadlessPaneD
|
|
|
296
301
|
}
|
|
297
302
|
}
|
|
298
303
|
model.snapshot.intradayHistories = intradayHistories;
|
|
299
|
-
model.freshness = chartFreshness(model.series);
|
|
304
|
+
model.freshness = chartFreshness(model.series, model.spec);
|
|
300
305
|
const priceDomainFailures = intradayHistories.flatMap(({ symbol, exchange, priceDomainFailure }) =>
|
|
301
306
|
priceDomainFailure ? [{ symbol, exchange, ...priceDomainFailure }] : []);
|
|
302
307
|
if (priceDomainFailures.length) {
|
|
@@ -13,6 +13,8 @@ import type { ChartSpec } from "../../../time-series/types";
|
|
|
13
13
|
import { isPriceOnlyMarketFieldId } from "../../../time-series/field-catalog";
|
|
14
14
|
import { ChartComposerPane, ChartComposerResearchTab } from "./pane";
|
|
15
15
|
import { DataCatalogPane } from "./data-catalog-pane";
|
|
16
|
+
import { listFieldSeries } from "./field-series";
|
|
17
|
+
import { registeredSeriesName } from "./series-expression";
|
|
16
18
|
import {
|
|
17
19
|
CHART_COMPOSER_TEMPLATE_ID,
|
|
18
20
|
DATA_CATALOG_PANE_ID,
|
|
@@ -104,7 +106,7 @@ function chartTitle(spec: ChartSpec, prefix = "G"): string {
|
|
|
104
106
|
? tickerInstrumentLabel(publicTickerKey(series.source.instrument.symbol, series.source.instrument.exchange), series.source.instrument.instrument)
|
|
105
107
|
: series.source.kind === "economic"
|
|
106
108
|
? `FRED:${series.source.seriesId}`
|
|
107
|
-
: series.label?.trim() || series.source.seriesId
|
|
109
|
+
: series.label?.trim() || registeredSeriesName(series.source) || series.source.seriesId
|
|
108
110
|
));
|
|
109
111
|
if (labels.length === 0) return "Custom Chart";
|
|
110
112
|
const remaining = spec.series.length - labels.length;
|
|
@@ -319,7 +321,7 @@ const chartComposerTemplates: PaneTemplateDef[] = [
|
|
|
319
321
|
id: DATA_CATALOG_TEMPLATE_ID,
|
|
320
322
|
paneId: DATA_CATALOG_PANE_ID,
|
|
321
323
|
label: "Data Catalog",
|
|
322
|
-
description: "Browse and search
|
|
324
|
+
description: "Browse and search every series a chart can draw: securities, rates, credit, economic data, volatility, sentiment, positioning and your own files.",
|
|
323
325
|
keywords: [
|
|
324
326
|
"catalog",
|
|
325
327
|
"series",
|
|
@@ -331,6 +333,9 @@ const chartComposerTemplates: PaneTemplateDef[] = [
|
|
|
331
333
|
"crypto",
|
|
332
334
|
"options",
|
|
333
335
|
"option",
|
|
336
|
+
"credit",
|
|
337
|
+
"sentiment",
|
|
338
|
+
"positioning",
|
|
334
339
|
],
|
|
335
340
|
shortcut: { prefix: "CAT", argPlaceholder: "query", argKind: "text", argOptional: true },
|
|
336
341
|
canCreate: () => true,
|
|
@@ -424,6 +429,8 @@ function chartShowsOneSecurity(pane: PaneInstanceConfig): boolean {
|
|
|
424
429
|
}
|
|
425
430
|
|
|
426
431
|
export const chartComposerModule: PluginModule = {
|
|
432
|
+
// Every ticker field, asking for the ticker when charted.
|
|
433
|
+
series: listFieldSeries(),
|
|
427
434
|
panes: [{
|
|
428
435
|
id: CHART_COMPOSER_PANE_ID,
|
|
429
436
|
name: "Chart",
|
|
@@ -7,11 +7,7 @@ import {
|
|
|
7
7
|
type ChartSeriesCatalogItem,
|
|
8
8
|
} from "../../../capabilities";
|
|
9
9
|
import type { TimeSeriesFieldDefinition } from "../../../time-series/types";
|
|
10
|
-
import {
|
|
11
|
-
FUTURES_CONTRACTS,
|
|
12
|
-
FUTURES_SECTOR_LABELS,
|
|
13
|
-
} from "../futures/contracts";
|
|
14
|
-
import { TREASURY_MATURITIES } from "../yield-curve/treasury-data";
|
|
10
|
+
import type { SeriesCatalogEntry } from "../../../series/types";
|
|
15
11
|
import {
|
|
16
12
|
canonicalExchange,
|
|
17
13
|
parsePublicTickerKey,
|
|
@@ -271,50 +267,61 @@ function matchesAliasQuery(query: string, ...values: string[]): boolean {
|
|
|
271
267
|
return tokens.length > 0 && tokens.every((token) => searchable.includes(token));
|
|
272
268
|
}
|
|
273
269
|
|
|
274
|
-
function
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
270
|
+
function suggestionId(expression: ParsedSeriesExpression): string {
|
|
271
|
+
if (expression.kind === "economic") return `fred:${expression.seriesId}`;
|
|
272
|
+
if (expression.kind === "capability") {
|
|
273
|
+
return chartSeriesSourceKey({ kind: "capability", capabilityId: expression.capabilityId, seriesId: expression.seriesId });
|
|
274
|
+
}
|
|
275
|
+
return `${publicTickerKey(expression.symbol, expression.exchange)}:${expression.fieldId}`;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function registeredMatchRank(entry: SeriesCatalogEntry, query: string): number {
|
|
279
|
+
const name = compact(entry.name);
|
|
280
|
+
const needle = compact(query);
|
|
281
|
+
if (name === needle || compact(entry.expression) === needle) return 0;
|
|
282
|
+
if (name.startsWith(needle)) return 1;
|
|
283
|
+
return 2;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Registered catalog series the query names: by name, expression, group or
|
|
288
|
+
* tags. A series that takes a ticker is filled in with the one the query
|
|
289
|
+
* names, or the chart's own; ticker fields come from the field ranking instead.
|
|
290
|
+
*/
|
|
291
|
+
function registeredSeriesSuggestions(
|
|
292
|
+
query: string,
|
|
293
|
+
registered: readonly SeriesCatalogEntry[],
|
|
294
|
+
analysis: SeriesSearchAnalysis,
|
|
295
|
+
defaultInstrument: SeriesCatalogInstrument,
|
|
296
|
+
): SeriesCatalogSuggestion[] {
|
|
297
|
+
if (!query.trim() || registered.length === 0) return [];
|
|
298
|
+
const instrument = analysis.directInstrument ?? defaultInstrument;
|
|
299
|
+
const tickerQuery = analysis.directInstrument ? analysis.metricQuery : query;
|
|
300
|
+
const hits: Array<{ entry: SeriesCatalogEntry; rank: number; expression: ParsedSeriesExpression }> = [];
|
|
301
|
+
for (const entry of registered) {
|
|
302
|
+
let template = entry.expression;
|
|
303
|
+
let text = query;
|
|
304
|
+
if (entry.input) {
|
|
305
|
+
// Ticker fields are ranked against the security below; options and pairs need their own symbol.
|
|
306
|
+
if (entry.input !== "ticker" || /^\{ticker\}:[A-Za-z]/.test(template) || !tickerQuery.trim()) continue;
|
|
307
|
+
const symbol = publicTickerKey(instrument.symbol, instrument.exchange);
|
|
308
|
+
template = template.replaceAll("{ticker}", template.startsWith("CAP:") ? encodeURIComponent(symbol) : symbol);
|
|
309
|
+
text = tickerQuery;
|
|
310
|
+
}
|
|
311
|
+
if (!matchesAliasQuery(text, entry.name, entry.expression, entry.id, entry.group ?? "", ...(entry.tags ?? []))) continue;
|
|
312
|
+
const parsed = parseSeriesExpression(template);
|
|
313
|
+
if (!parsed) continue;
|
|
314
|
+
const label = entry.input ? `${publicTickerKey(instrument.symbol, instrument.exchange)} · ${entry.name}` : entry.name;
|
|
315
|
+
hits.push({ entry, rank: registeredMatchRank(entry, text), expression: { ...parsed, label } });
|
|
316
|
+
}
|
|
317
|
+
hits.sort((left, right) => left.rank - right.rank || left.entry.name.length - right.entry.name.length);
|
|
318
|
+
return hits.map(({ entry, expression }): SeriesCatalogSuggestion => ({
|
|
319
|
+
id: suggestionId(expression),
|
|
320
|
+
label: expression.kind === "capability" ? expression.label ?? entry.name : `${entry.expression} · ${entry.name}`,
|
|
321
|
+
description: [entry.group, entry.unit, entry.frequency].filter(Boolean).join(" · "),
|
|
322
|
+
detail: entry.group ?? "Series",
|
|
323
|
+
expression,
|
|
324
|
+
}));
|
|
318
325
|
}
|
|
319
326
|
|
|
320
327
|
export function buildCapabilitySeriesSuggestions(
|
|
@@ -345,6 +352,7 @@ export function buildSeriesCatalogSuggestions(
|
|
|
345
352
|
defaultInstrument: SeriesCatalogInstrument,
|
|
346
353
|
searchedInstruments: readonly SeriesCatalogInstrument[] = [],
|
|
347
354
|
limit = 8,
|
|
355
|
+
registered: readonly SeriesCatalogEntry[] = [],
|
|
348
356
|
): SeriesCatalogSuggestion[] {
|
|
349
357
|
const exact = exactExpressionSuggestion(query.trim());
|
|
350
358
|
const analysis = analyzeSeriesSearchQuery(query);
|
|
@@ -362,7 +370,7 @@ export function buildSeriesCatalogSuggestions(
|
|
|
362
370
|
.sort((left, right) => right.score - left.score || left.field.label.localeCompare(right.field.label));
|
|
363
371
|
|
|
364
372
|
const suggestions: SeriesCatalogSuggestion[] = exact ? [exact] : [];
|
|
365
|
-
for (const suggestion of
|
|
373
|
+
for (const suggestion of registeredSeriesSuggestions(query, registered, analysis, defaultInstrument)) {
|
|
366
374
|
if (!suggestions.some((entry) => entry.id === suggestion.id)) suggestions.push(suggestion);
|
|
367
375
|
}
|
|
368
376
|
const fieldLimit = instruments.length > 1 && !analysis.metricQuery ? 1 : rankedFields.length;
|
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
isValidChartCapabilityId,
|
|
16
16
|
isValidChartSeriesId,
|
|
17
17
|
} from "../../../capabilities/chart-series";
|
|
18
|
-
import {
|
|
18
|
+
import { futuresContractByCode } from "../../../market-data/futures-board";
|
|
19
|
+
import { getSharedRegistry } from "../../registry";
|
|
19
20
|
import { TREASURY_MATURITIES } from "../yield-curve/treasury-data";
|
|
20
21
|
|
|
21
22
|
export const CHART_FIELD_IDS = {
|
|
@@ -100,9 +101,9 @@ export function parseSeriesExpression(value: string): ParsedSeriesExpression | n
|
|
|
100
101
|
if (separator < 0) return null;
|
|
101
102
|
const capabilityId = trimmed.slice(4, separator);
|
|
102
103
|
const seriesId = trimmed.slice(separator + 1);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
if (!isValidChartCapabilityId(capabilityId) || !isValidChartSeriesId(seriesId)) return null;
|
|
105
|
+
const label = registeredSeriesName({ capabilityId, seriesId });
|
|
106
|
+
return { kind: "capability", capabilityId, seriesId, ...(label ? { label } : {}) };
|
|
106
107
|
}
|
|
107
108
|
if (parts[0]?.trim().toUpperCase() === "GEO") {
|
|
108
109
|
const seriesId = trimmed.slice(trimmed.indexOf(":") + 1).trim();
|
|
@@ -112,13 +113,13 @@ export function parseSeriesExpression(value: string): ParsedSeriesExpression | n
|
|
|
112
113
|
}
|
|
113
114
|
if (parts[0]?.trim().toUpperCase() === "FRED") {
|
|
114
115
|
const seriesId = parts.length === 2 ? parts[1]?.trim().toUpperCase() ?? "" : "";
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
if (!/^[A-Z0-9._-]{1,80}$/.test(seriesId)) return null;
|
|
117
|
+
// The catalog's name for a listed series, so the legend says what the catalog said.
|
|
118
|
+
const label = getSharedRegistry()?.series?.findByExpression(`FRED:${seriesId}`)?.definition.name;
|
|
119
|
+
return { kind: "economic", provider: "fred", seriesId, ...(label ? { label } : {}) };
|
|
118
120
|
}
|
|
119
121
|
if (parts.length === 2 && parts[0]?.trim().toUpperCase() === "FUT") {
|
|
120
|
-
const
|
|
121
|
-
const contract = FUTURES_CONTRACTS.find((entry) => entry.code === code);
|
|
122
|
+
const contract = futuresContractByCode(parts[1]);
|
|
122
123
|
return contract
|
|
123
124
|
? { kind: "security", symbol: contract.symbol, fieldId: CHART_FIELD_IDS.price, label: contract.name }
|
|
124
125
|
: null;
|
|
@@ -189,10 +190,17 @@ export function formatSeriesExpression(series: ChartSeriesSpec): string {
|
|
|
189
190
|
return `${publicTickerKey(series.source.instrument.symbol, series.source.instrument.exchange)}:${series.source.fieldId}`;
|
|
190
191
|
}
|
|
191
192
|
|
|
193
|
+
/** A registered catalog series' name, with the ticker it was charted for. */
|
|
194
|
+
export function registeredSeriesName(source: { capabilityId: string; seriesId: string }): string | null {
|
|
195
|
+
const found = getSharedRegistry()?.series?.findLoaded(source.capabilityId, source.seriesId);
|
|
196
|
+
if (!found) return null;
|
|
197
|
+
return found.ticker ? `${found.ticker} ${found.series.definition.name}` : found.series.definition.name;
|
|
198
|
+
}
|
|
199
|
+
|
|
192
200
|
export function chartSeriesLabel(series: ChartSeriesSpec): string {
|
|
193
201
|
if (series.label?.trim()) return series.label.trim();
|
|
194
202
|
if (series.source.kind === "economic") return `FRED ${series.source.seriesId}`;
|
|
195
|
-
if (series.source.kind === "capability") return series.source.seriesId;
|
|
203
|
+
if (series.source.kind === "capability") return registeredSeriesName(series.source) ?? series.source.seriesId;
|
|
196
204
|
const generic = getTimeSeriesField(series.source.fieldId)?.unitGroup === "price"
|
|
197
205
|
? futuresGenericListing(series.source.instrument.symbol, series.source.instrument.exchange) : null;
|
|
198
206
|
if (generic) return futuresGenericCaption(generic);
|