gloomberb 0.16.3 → 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 +7 -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 +42 -17
- package/src/account/upgrade-personalization.ts +57 -0
- package/src/account/upgrade-tickers.ts +124 -0
- package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
- package/src/api-client/askg.ts +43 -0
- package/src/api-client/auth.ts +15 -0
- package/src/api-client/beneficial-owners.ts +4 -0
- package/src/api-client/chat.ts +19 -0
- package/src/api-client/company-kpis.ts +14 -2
- package/src/api-client/data.ts +58 -18
- package/src/api-client/earnings.ts +6 -0
- package/src/api-client/futures-curve.ts +56 -0
- package/src/api-client/index.ts +16 -1
- package/src/api-client/market-discovery.ts +10 -1
- package/src/api-client/normalizers.ts +27 -0
- package/src/api-client/paths.ts +95 -23
- package/src/api-client/request.ts +2 -1
- package/src/api-client/research-activity.ts +46 -10
- package/src/api-client/socket.ts +39 -8
- package/src/api-client/types.ts +74 -2
- package/src/api-client/upgrade-experiment.ts +90 -0
- package/src/api-client/yield-curves.ts +8 -0
- package/src/app/global-shortcuts.ts +26 -2
- package/src/app/keybindings/actions.ts +10 -0
- package/src/app/pane-runtime/index.tsx +8 -0
- package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
- package/src/app/pane-runtime/plugin-bindings.ts +65 -25
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +25 -4
- package/src/app/runtime/desktop-deeplink.ts +5 -0
- package/src/app/star-prompt/model.ts +98 -0
- package/src/app/star-prompt/runtime.ts +41 -0
- package/src/app/star-prompt/status-line.tsx +190 -0
- package/src/app.tsx +13 -7
- package/src/architecture/core-builtin-allowlist.json +61 -0
- package/src/brokers/signed-in/adapter.ts +33 -2
- package/src/brokers/signed-in/client.ts +10 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +34 -14
- package/src/brokers/signed-in/sign-in.ts +62 -5
- package/src/capabilities/chart-series.ts +11 -1
- package/src/capabilities/registry.ts +8 -1
- package/src/capabilities/types.ts +2 -0
- package/src/cli/commands/crypto-hints.ts +19 -4
- package/src/cli/commands/fred-series.ts +61 -0
- package/src/cli/commands/market.ts +744 -181
- package/src/cli/commands/news-hints.ts +62 -0
- package/src/cli/commands/news-search.ts +53 -0
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +425 -0
- package/src/cli/commands/overview.ts +251 -40
- package/src/cli/commands/remote.ts +2 -1
- package/src/cli/commands/search.ts +109 -15
- package/src/cli/commands/system.ts +151 -24
- package/src/cli/commands/themes.ts +64 -0
- package/src/cli/commands/ticker.ts +149 -40
- package/src/cli/context.ts +45 -14
- package/src/cli/desktop-pane-shot.ts +150 -17
- package/src/cli/earnings-calendar.ts +71 -0
- package/src/cli/errors.ts +25 -2
- package/src/cli/freshness.ts +22 -8
- package/src/cli/fx-pair.ts +57 -0
- package/src/cli/glossary.ts +429 -0
- package/src/cli/help.ts +14 -1
- package/src/cli/history-rows.ts +48 -7
- package/src/cli/index-roots.ts +58 -0
- package/src/cli/index.ts +29 -12
- package/src/cli/known-gaps.ts +27 -0
- package/src/cli/listing-arg.ts +595 -26
- package/src/cli/not-a-ticker.ts +44 -0
- package/src/cli/options.ts +50 -6
- package/src/cli/pane-functions/access-gate.ts +5 -0
- package/src/cli/pane-functions/capabilities.ts +11 -4
- package/src/cli/pane-functions/catalog.ts +48 -7
- package/src/cli/pane-functions/data.ts +48 -13
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/dom.ts +41 -19
- package/src/cli/pane-functions/freshness.ts +531 -32
- package/src/cli/pane-functions/function-help.ts +77 -25
- package/src/cli/pane-functions/headless.ts +50 -21
- package/src/cli/pane-functions/index.ts +66 -10
- package/src/cli/pane-functions/market-session.ts +147 -0
- package/src/cli/pane-functions/options.ts +77 -25
- package/src/cli/pane-functions/report-notices.ts +81 -0
- package/src/cli/pane-functions/report.ts +19 -8
- package/src/cli/pane-functions/resolver.ts +53 -18
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +199 -30
- package/src/cli/registry.ts +2 -1
- package/src/cli/report-tables.ts +3 -0
- package/src/cli/result.ts +53 -13
- package/src/cli/row-window.ts +76 -0
- package/src/cli/scroll-truncation.ts +34 -0
- 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 +83 -10
- package/src/components/chart/composite/legend.tsx +88 -8
- package/src/components/chart/composite/panel-surface.tsx +44 -17
- package/src/components/chart/composite/price-axis-labels.tsx +3 -1
- package/src/components/chart/composite/rasterizer.ts +64 -4
- package/src/components/chart/composite/series-cues.ts +71 -0
- package/src/components/chart/composite/text-renderer.ts +16 -8
- package/src/components/chart/composite/types.ts +3 -0
- package/src/components/command-bar/commands/direct/index.ts +9 -1
- package/src/components/command-bar/commands/plugin/items.ts +3 -1
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
- package/src/components/command-bar/pane-templates/workflow.ts +5 -0
- 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/command-items.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
- package/src/components/command-bar/routes/root/provider-search.ts +4 -3
- package/src/components/command-bar/routes/root/results.ts +40 -10
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/root/search-providers.ts +97 -14
- 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/surface/index.tsx +18 -4
- package/src/components/command-bar/theme-picker.tsx +48 -13
- package/src/components/command-bar/workflow/ops.ts +5 -3
- package/src/components/command-bar/workflow/tickers.ts +23 -4
- package/src/components/data-table/view.tsx +28 -9
- package/src/components/layout/detached-pane-shell.tsx +9 -0
- package/src/components/layout/floating-pane.tsx +9 -2
- package/src/components/layout/header.tsx +20 -5
- package/src/components/layout/market-summary.ts +23 -9
- package/src/components/layout/pane/content.tsx +40 -29
- package/src/components/layout/pane/cycle-order.ts +2 -11
- 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 +26 -2
- package/src/components/layout/pane/index.tsx +12 -2
- package/src/components/layout/pane/sidebar.tsx +78 -10
- package/src/components/layout/pane/title.ts +1 -1
- package/src/components/layout/presentation.ts +22 -0
- package/src/components/layout/shell/active-drag.ts +21 -5
- package/src/components/layout/shell/drag/index.ts +43 -9
- package/src/components/layout/shell/drag/live.ts +87 -6
- package/src/components/layout/shell/drag/runtime.ts +62 -20
- package/src/components/layout/shell/index.tsx +71 -12
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +33 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +216 -28
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/pane/new-layout.ts +116 -0
- package/src/components/layout/shell/shortcuts.ts +5 -2
- package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
- package/src/components/layout/shell/visible-layout.ts +44 -1
- package/src/components/layout/status-bar.tsx +4 -1
- package/src/components/markdown-text.tsx +69 -23
- package/src/components/metric-treemap/heat-surface.tsx +37 -9
- package/src/components/metric-treemap/heat-tiles.ts +48 -17
- 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-frame.tsx +33 -10
- package/src/components/onboarding/onboarding-keyboard.ts +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +50 -41
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
- package/src/components/onboarding/pro-step-layout.ts +86 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +8 -4
- 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 +17 -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 +49 -0
- package/src/components/ui/data-table/opentui/index.tsx +37 -6
- package/src/components/ui/data-table/types.ts +20 -1
- package/src/components/ui/data-table/visible-range.ts +2 -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 +13 -2
- package/src/components/ui/index.ts +1 -1
- package/src/components/ui/text-prompt-dialog.tsx +11 -9
- package/src/core/connection-health.ts +1 -1
- package/src/core/state/app/layout-reducer.ts +89 -3
- package/src/core/state/app/state.ts +8 -5
- package/src/core/state/app/types.ts +13 -2
- package/src/data/cached-query.ts +2 -0
- package/src/data/config/layout.ts +55 -21
- package/src/data/config/store/fold-panes.ts +149 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/node.ts +27 -6
- package/src/data/config/store/normalize.ts +44 -5
- 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 +75 -5
- package/src/i18n/ja.ts +75 -5
- package/src/i18n/ko.ts +75 -5
- package/src/i18n/zh-cn.ts +75 -5
- package/src/i18n/zh-tw.ts +75 -5
- package/src/layout/desks.ts +2 -3
- package/src/layout/pane-layout-move.ts +264 -0
- package/src/layout/pane-manager/dock-tree.ts +18 -0
- package/src/layout/pane-manager/hidden-panes.ts +160 -0
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/market-data/coordinator/chart.ts +10 -4
- package/src/market-data/coordinator/entries.ts +7 -1
- package/src/market-data/coordinator/index.ts +6 -3
- package/src/market-data/coordinator/quotes.ts +2 -2
- 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 +193 -30
- package/src/market-data/market/status.ts +59 -23
- package/src/market-data/options-alternatives.ts +69 -0
- package/src/market-data/published-apac-sessions.ts +23 -1
- package/src/market-data/quotes/contributions.ts +22 -2
- package/src/market-data/quotes/metadata.ts +8 -9
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +61 -9
- package/src/market-data/result-types.ts +2 -0
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +2 -56
- package/src/plugins/builtin/account-management/navigation.ts +1 -1
- package/src/plugins/builtin/account-management/pane.tsx +37 -8
- 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/quotes.ts +3 -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 +33 -13
- package/src/plugins/builtin/analytics/risk-math.ts +91 -27
- package/src/plugins/builtin/analytics/risk-model.ts +71 -12
- package/src/plugins/builtin/analytics/risk-pane.tsx +23 -12
- 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/backtest/pane.tsx +1 -1
- package/src/plugins/builtin/bond-calculator/model.ts +2 -1
- package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/broker-manager/model.ts +8 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
- package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
- package/src/plugins/builtin/broker-manager/table.ts +5 -0
- package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
- 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/pane.tsx +1 -1
- 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/channels.ts +34 -36
- package/src/plugins/builtin/chat/command-bar.ts +138 -0
- package/src/plugins/builtin/chat/composer-commands.ts +21 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
- package/src/plugins/builtin/chat/content/footer.tsx +5 -3
- package/src/plugins/builtin/chat/content/index.tsx +21 -1
- package/src/plugins/builtin/chat/content/mentions.ts +2 -1
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
- package/src/plugins/builtin/chat/content/user-map.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +50 -0
- package/src/plugins/builtin/chat/conversations.ts +256 -0
- package/src/plugins/builtin/chat/discord-command.ts +91 -0
- package/src/plugins/builtin/chat/edit-window.ts +12 -6
- package/src/plugins/builtin/chat/ghost-user.ts +14 -0
- package/src/plugins/builtin/chat/index.tsx +40 -2
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
- package/src/plugins/builtin/chat/message/header.tsx +24 -15
- package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
- package/src/plugins/builtin/chat/message/render-state.ts +3 -0
- package/src/plugins/builtin/chat/pane-requests.ts +60 -0
- package/src/plugins/builtin/chat/pane-state.ts +32 -2
- package/src/plugins/builtin/chat/pane.tsx +8 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +223 -23
- package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
- package/src/plugins/builtin/cloud/askg/manifest.ts +33 -7
- package/src/plugins/builtin/cloud/askg/model.ts +156 -78
- package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
- package/src/plugins/builtin/cloud/askg/protocol.ts +50 -3
- package/src/plugins/builtin/cloud/askg/tool-display.ts +440 -0
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -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 -9
- package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +363 -0
- package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
- package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
- package/src/plugins/builtin/cloud/plugin.tsx +36 -1
- package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
- package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
- package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +734 -0
- package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
- package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
- package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +239 -0
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +162 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +192 -0
- package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
- package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
- package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
- package/src/plugins/builtin/comment-letters/client.ts +1 -3
- 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/client.ts +23 -8
- package/src/plugins/builtin/company-kpis/headless.ts +3 -1
- package/src/plugins/builtin/company-kpis/pane.tsx +19 -9
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
- package/src/plugins/builtin/composite-plugins.ts +116 -67
- 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/cdx-pane.tsx +4 -4
- package/src/plugins/builtin/credit-boards/index.tsx +23 -21
- package/src/plugins/builtin/credit-boards/model.ts +0 -1
- package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
- package/src/plugins/builtin/credit-boards/series.ts +66 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
- 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/client.ts +37 -9
- package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
- package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
- 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 +3 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- 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/earnings-calls/data.ts +28 -7
- package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +42 -17
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- 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 +70 -22
- package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +30 -5
- package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
- package/src/plugins/builtin/econ-statistics/view.ts +17 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
- package/src/plugins/builtin/executives/data.ts +17 -6
- package/src/plugins/builtin/executives/pane.tsx +16 -7
- 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/filing-events/pane.tsx +22 -5
- 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 +22 -1
- package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
- package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
- 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 +64 -27
- 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 +114 -20
- 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 +18 -8
- package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
- 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 +62 -14
- 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 +42 -134
- package/src/plugins/builtin/holders/pane.tsx +14 -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 +27 -10
- 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/charts.tsx +21 -7
- package/src/plugins/builtin/iv-history/client.ts +26 -6
- package/src/plugins/builtin/iv-history/format.ts +33 -2
- package/src/plugins/builtin/iv-history/headless.ts +27 -12
- package/src/plugins/builtin/iv-history/index.tsx +5 -3
- package/src/plugins/builtin/iv-history/model.ts +172 -20
- package/src/plugins/builtin/iv-history/pane.tsx +11 -3
- package/src/plugins/builtin/iv-history/screen-pane.tsx +45 -25
- 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/pane.tsx +1 -1
- package/src/plugins/builtin/jobs/series.ts +19 -0
- package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
- package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +111 -40
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
- package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
- package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
- package/src/plugins/builtin/layout-manager/index.tsx +9 -1
- package/src/plugins/builtin/macro-day/client.ts +68 -3
- package/src/plugins/builtin/macro-day/headless.ts +18 -12
- package/src/plugins/builtin/macro-day/index.tsx +3 -0
- package/src/plugins/builtin/macro-day/model.ts +66 -15
- package/src/plugins/builtin/macro-day/pane.tsx +34 -20
- package/src/plugins/builtin/macro-day/release-table.ts +40 -0
- package/src/plugins/builtin/macro-day/releases.ts +62 -44
- package/src/plugins/builtin/market-heatmap/data.ts +25 -5
- package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
- package/src/plugins/builtin/market-heatmap/model.ts +102 -3
- package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
- package/src/plugins/builtin/market-movers/client.ts +7 -5
- package/src/plugins/builtin/market-movers/headless.ts +31 -4
- package/src/plugins/builtin/market-movers/index.tsx +11 -3
- package/src/plugins/builtin/market-movers/model.ts +101 -17
- package/src/plugins/builtin/market-movers/screener.ts +31 -0
- package/src/plugins/builtin/market-movers/table.ts +50 -23
- 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/news/headless.ts +9 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
- package/src/plugins/builtin/notes/cli.ts +12 -7
- package/src/plugins/builtin/openfda/client.ts +1 -1
- package/src/plugins/builtin/options/carry.ts +95 -0
- package/src/plugins/builtin/options/index.tsx +58 -5
- package/src/plugins/builtin/options/strike-window.ts +183 -0
- package/src/plugins/builtin/options/table.ts +55 -3
- package/src/plugins/builtin/options/types.ts +8 -1
- package/src/plugins/builtin/options/view.tsx +162 -13
- 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 +5 -2
- package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
- package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +75 -18
- package/src/plugins/builtin/options-scenario/headless.ts +72 -24
- package/src/plugins/builtin/options-scenario/hedge.ts +285 -0
- package/src/plugins/builtin/options-scenario/index.tsx +9 -2
- package/src/plugins/builtin/options-scenario/model.ts +33 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
- package/src/plugins/builtin/pe-band/model.ts +2 -2
- package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
- package/src/plugins/builtin/perps/client.ts +40 -6
- package/src/plugins/builtin/perps/equity-row.tsx +33 -8
- 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 +32 -6
- package/src/plugins/builtin/perps/pane.tsx +76 -20
- package/src/plugins/builtin/perps/series.ts +76 -0
- package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
- package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +357 -39
- package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
- package/src/plugins/builtin/plugin-module.ts +90 -4
- 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 +400 -99
- package/src/plugins/builtin/portfolio-list/cli/render.ts +281 -43
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +26 -16
- 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 +70 -9
- 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 +8 -0
- package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +7 -4
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
- 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/revenue-breakdown/client.ts +13 -6
- package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
- package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
- package/src/plugins/builtin/risk-factors/data.ts +23 -9
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- 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/sec/index.tsx +5 -5
- package/src/plugins/builtin/sectors/client.ts +10 -2
- package/src/plugins/builtin/sectors/headless.ts +35 -6
- package/src/plugins/builtin/sectors/index.tsx +18 -1
- package/src/plugins/builtin/sectors/sector-model.ts +150 -41
- 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 +69 -0
- 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/headless-market-data.ts +33 -1
- package/src/plugins/builtin/shared/members-menu.tsx +4 -4
- package/src/plugins/builtin/shared/open-description.ts +29 -0
- package/src/plugins/builtin/shared/report-freshness.ts +59 -2
- package/src/plugins/builtin/shared/series-warning.ts +5 -0
- package/src/plugins/builtin/shared/ticker-request.ts +25 -1
- package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
- package/src/plugins/builtin/shared/volatility/options.ts +1 -46
- package/src/plugins/builtin/short-interest/headless.ts +1 -0
- package/src/plugins/builtin/short-interest/index.tsx +21 -4
- package/src/plugins/builtin/short-interest/series.ts +36 -0
- package/src/plugins/builtin/short-interest/surface.tsx +4 -4
- 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 +3 -10
- 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/model.ts +1 -1
- 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/headless.ts +43 -21
- 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/pane.tsx +4 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
- 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/cache.ts +5 -2
- package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
- package/src/plugins/builtin/treasury-auctions/headless.ts +56 -6
- package/src/plugins/builtin/treasury-auctions/index.tsx +12 -9
- package/src/plugins/builtin/treasury-auctions/model.ts +205 -30
- package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
- package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
- package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
- package/src/plugins/builtin/vol-surface/client.ts +6 -2
- package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
- package/src/plugins/builtin/vol-surface/headless.ts +125 -20
- package/src/plugins/builtin/vol-surface/model.ts +23 -11
- package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
- package/src/plugins/builtin/vol-surface/tables.ts +124 -0
- package/src/plugins/builtin/volatility/index.tsx +2 -0
- package/src/plugins/builtin/volatility/series.ts +84 -0
- package/src/plugins/builtin/world-indices/client.ts +22 -4
- package/src/plugins/builtin/world-indices/headless.ts +54 -27
- package/src/plugins/builtin/world-indices/model.ts +4 -2
- package/src/plugins/builtin/world-indices/table.tsx +13 -2
- package/src/plugins/builtin/world-venue-map/geo-series.ts +27 -2
- package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -2
- 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 +4 -2
- package/src/plugins/builtin/yield-curve/series.ts +86 -0
- package/src/plugins/builtin-editorial.ts +126 -0
- package/src/plugins/catalog-backend.ts +16 -9
- package/src/plugins/catalog-browser.ts +129 -64
- package/src/plugins/catalog-manifest.ts +73 -40
- package/src/plugins/catalog-ui.ts +26 -6
- package/src/plugins/extracted-plugins.ts +7 -1
- package/src/plugins/ownership.ts +150 -7
- package/src/plugins/plugin-functions.ts +54 -0
- package/src/plugins/plugin-off.ts +36 -0
- package/src/plugins/registry/host-actions.ts +16 -0
- package/src/plugins/registry/index.ts +173 -28
- package/src/plugins/registry/plugin-state.ts +25 -1
- package/src/plugins/runtime/context.tsx +29 -0
- 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/react/input.ts +48 -1
- package/src/remote/app-host.tsx +25 -4
- package/src/remote/confirm-change.tsx +85 -0
- package/src/remote/controller-utils.ts +8 -1
- package/src/remote/controller.ts +126 -59
- package/src/remote/matching.ts +69 -0
- package/src/remote/pane-screenshot.ts +47 -0
- package/src/remote/schema.ts +63 -1
- package/src/remote/semantic-tree.tsx +14 -0
- package/src/remote/types.ts +32 -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 +21 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/dom-ui-host.tsx +3 -0
- package/src/renderers/dom/host/box.tsx +4 -1
- package/src/renderers/dom/host/chart-surface.tsx +6 -2
- package/src/renderers/dom/host/drag-shield.ts +17 -6
- package/src/renderers/dom/host/live-frame.ts +14 -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/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +74 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +18 -3
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +109 -5
- package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
- package/src/renderers/electrobun/view/main.tsx +6 -1
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -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/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +26 -17
- package/src/sources/gloomberb-cloud/normalizers.ts +5 -1
- package/src/sources/history-result.ts +1 -0
- package/src/sources/listing-symbols.ts +14 -5
- package/src/sources/provider-errors.ts +88 -3
- 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 +9 -5
- package/src/sources/provider-router/financial-routes.ts +12 -5
- package/src/sources/provider-router/financials.ts +55 -15
- package/src/sources/provider-router/history.ts +68 -34
- package/src/sources/provider-router/index.ts +1 -1
- package/src/sources/provider-router/primary.ts +23 -5
- package/src/sources/provider-router/search.ts +1 -0
- package/src/sources/sec-edgar.ts +68 -8
- package/src/sync/core-contributors.ts +5 -3
- package/src/test-support/cli-context.ts +2 -1
- package/src/test-support/data-provider.ts +34 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/series-colors.ts +46 -0
- package/src/theme/themes.ts +149 -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 +67 -9
- package/src/tickers/search/ranking.ts +78 -18
- package/src/tickers/search/types.ts +10 -2
- package/src/tickers/starter-symbols.ts +8 -0
- package/src/tickers/us-listing.ts +34 -0
- package/src/time-series/hooks.ts +9 -0
- package/src/time-series/resolve.ts +96 -30
- package/src/time-series/types.ts +4 -2
- package/src/time-series/use-chart-resolution.ts +32 -0
- package/src/types/config.ts +67 -1
- package/src/types/data-provider.ts +5 -0
- package/src/types/financials.ts +52 -1
- package/src/types/headless.ts +72 -0
- package/src/types/instrument.ts +8 -0
- package/src/types/plugin.ts +68 -3
- package/src/types/price-history.ts +7 -0
- package/src/types/ticker.ts +14 -0
- package/src/ui/host.tsx +26 -4
- package/src/ui/index.tsx +2 -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 +21 -2
- 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 +120 -1
- package/src/utils/format.ts +17 -3
- package/src/utils/fundamentals.ts +66 -0
- package/src/utils/futures-generic.ts +6 -12
- package/src/utils/fx-market-hours.ts +44 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history.ts +130 -40
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +178 -36
- package/src/utils/sec.ts +98 -40
- package/src/utils/throttled-fetch.ts +51 -22
- package/src/utils/utc-time.ts +51 -4
|
@@ -2,8 +2,8 @@ import { saveConfig } from "../../../../data/config/store";
|
|
|
2
2
|
import { withConfigData, withMarketData } from "../../../../cli/scoped-context";
|
|
3
3
|
import { countCollectionTickers } from "../../../../cli/helpers";
|
|
4
4
|
import { resolveTickerForCli } from "../../../../cli/ticker-resolution";
|
|
5
|
-
import { takeOption } from "../../../../cli/commands/command-utils";
|
|
6
|
-
import { EXCHANGE_OPTION, loadSavedListing, parseListingArg, requireListingArg, savedListingName } from "../../../../cli/listing-arg";
|
|
5
|
+
import { takeFlag, takeOption } from "../../../../cli/commands/command-utils";
|
|
6
|
+
import { EXCHANGE_OPTION, listingKeys, loadSavedListing, parseListingArg, requireListingArg, savedListingName } from "../../../../cli/listing-arg";
|
|
7
7
|
import { cliStyles, renderStats, renderTable } from "../../../../utils/cli-output";
|
|
8
8
|
import { CLI_COMMAND_GROUPS } from "../../../../cli/help";
|
|
9
9
|
import { formatMarketCostWithCurrency, formatMarketQuantity } from "../../../../market-data/market/format";
|
|
@@ -11,7 +11,8 @@ import type { AppConfig } from "../../../../types/config";
|
|
|
11
11
|
import type { CliCommandContext, CliCommandDef } from "../../../../types/plugin";
|
|
12
12
|
import type { Portfolio, TickerRecord } from "../../../../types/ticker";
|
|
13
13
|
import type { TickerRepository } from "../../../../data/ticker-repository";
|
|
14
|
-
import {
|
|
14
|
+
import type { ConfigContext, MarketContext } from "../../../../cli/types";
|
|
15
|
+
import { canonicalTickerKey, parsePublicTickerKey } from "../../../../utils/exchanges";
|
|
15
16
|
import {
|
|
16
17
|
addTickerToPortfolio,
|
|
17
18
|
adoptFirstPositionCurrency,
|
|
@@ -27,7 +28,7 @@ import {
|
|
|
27
28
|
setPortfolioCash,
|
|
28
29
|
setPortfolioTargetWeight,
|
|
29
30
|
} from "../mutations";
|
|
30
|
-
import { renderCollectionOverview, showCollection } from "./render";
|
|
31
|
+
import { listingLabel, renderCollectionOverview, showCollection } from "./render";
|
|
31
32
|
import { resolvePortfolioTotalsCurrency } from "../summary/totals";
|
|
32
33
|
import {
|
|
33
34
|
CASH_SYMBOL,
|
|
@@ -37,8 +38,10 @@ import {
|
|
|
37
38
|
parseTargetWeight,
|
|
38
39
|
} from "../allocation";
|
|
39
40
|
import { findCachedPortfolioAccount } from "../cached-account";
|
|
41
|
+
import { apiClient } from "../../../../api-client";
|
|
42
|
+
import { importSource, notionalPositions, rankThirteenFLines, type ThirteenFImportLine } from "./import-13f";
|
|
43
|
+
import { importedFromText } from "../imported-from";
|
|
40
44
|
import {
|
|
41
|
-
describeTicker,
|
|
42
45
|
failPortfolioCommand,
|
|
43
46
|
isCashArgument,
|
|
44
47
|
listingFields,
|
|
@@ -47,10 +50,20 @@ import {
|
|
|
47
50
|
rejectCashSymbol,
|
|
48
51
|
requireManualPortfolio,
|
|
49
52
|
requirePortfolio,
|
|
53
|
+
takeCollectionName,
|
|
50
54
|
} from "./shared";
|
|
55
|
+
import { addSymbols, FILE_OPTION, printSymbolRows, removeSymbols, requireSymbolList, retryNotice, SYMBOL_LIST_HELP } from "./bulk-symbols";
|
|
51
56
|
|
|
57
|
+
const ADD_USAGE = "Usage: gloomberb portfolio add <portfolio> <symbols...> [--file <path>]";
|
|
58
|
+
const REMOVE_USAGE = "Usage: gloomberb portfolio remove <portfolio> <symbols...> [--file <path>]";
|
|
52
59
|
const CASH_USAGE = "Usage: gloomberb portfolio cash set <portfolio> <amount> [currency] | portfolio cash clear <portfolio>";
|
|
53
60
|
const TARGET_USAGE = "Usage: gloomberb portfolio target set <portfolio> <symbol|CASH> <weight%> | target clear <portfolio> [symbol] | target show <portfolio>";
|
|
61
|
+
const IMPORT_USAGE = "Usage: gloomberb portfolio import --13f <CIK|fund name> [--top N] [--name <portfolio>] [--notional <amount>] [--replace]";
|
|
62
|
+
const IMPORT_DEFAULT_TOP = 10;
|
|
63
|
+
const IMPORT_MAX_TOP = 100;
|
|
64
|
+
const IMPORT_DEFAULT_NOTIONAL = 100_000;
|
|
65
|
+
/** 13F lines read for an import: the largest, so skipped lines still leave enough for --top. */
|
|
66
|
+
const IMPORT_13F_ROWS = 200;
|
|
54
67
|
|
|
55
68
|
async function listCollections(ctx: CliCommandContext) {
|
|
56
69
|
await withConfigData(ctx, async ({ config, store }) => {
|
|
@@ -113,25 +126,68 @@ async function deletePortfolioCommand(name: string, ctx: CliCommandContext) {
|
|
|
113
126
|
});
|
|
114
127
|
}
|
|
115
128
|
|
|
116
|
-
|
|
117
|
-
|
|
129
|
+
/** The manual portfolio the leading arguments name and the symbols after it; fails naming the portfolios there are. */
|
|
130
|
+
function requirePortfolioArgs(config: AppConfig, args: readonly string[], usage: string, ctx: CliCommandContext): { portfolio: Portfolio; rest: string[] } {
|
|
131
|
+
if (args.length === 0) ctx.fail(usage);
|
|
132
|
+
const match = takeCollectionName(args, config.portfolios);
|
|
133
|
+
try {
|
|
134
|
+
// A name nothing matches is reported as typed: its first argument, never the symbols glued on.
|
|
135
|
+
return { portfolio: requireManualPortfolio(config, match?.collection.id ?? args[0]!), rest: match?.rest ?? [] };
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return failPortfolioCommand(ctx, error, `Portfolio "${args[0]}" was not found.`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Bare CASH is the cash line, which add and remove refuse with the hint `rejectCashSymbol` gives. */
|
|
142
|
+
function cashRefusal(portfolio: Portfolio, exchange: string | undefined) {
|
|
143
|
+
return (input: string): Error | null => {
|
|
118
144
|
try {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const ticker = await resolveTickerForCli(symbol, store, dataProvider, exchange);
|
|
122
|
-
const result = addTickerToPortfolio(ticker, portfolio.id);
|
|
123
|
-
// Name the listing that was stored: SAN:EPA is not the SAN that a bare SAN means.
|
|
124
|
-
const saved = savedListingName(ticker);
|
|
125
|
-
const data = { changed: result.changed, ...listingFields(saved), portfolio: portfolio.name };
|
|
126
|
-
if (!result.changed) {
|
|
127
|
-
ctx.printResult({ data }, { text: () => cliStyles.warning(`${saved.label} is already in "${portfolio.name}".`) });
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
await store.saveTicker(result.ticker);
|
|
131
|
-
ctx.printResult({ data }, { text: () => cliStyles.success(`Added ${saved.label} to "${portfolio.name}".`) });
|
|
145
|
+
rejectCashSymbol(input, exchange, portfolio.name);
|
|
146
|
+
return null;
|
|
132
147
|
} catch (error) {
|
|
133
|
-
|
|
148
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
134
149
|
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function addTickerToPortfolioCommand(portfolio: Portfolio, symbol: string, exchange: string | undefined, ctx: CliCommandContext, { store, dataProvider }: MarketContext) {
|
|
154
|
+
try {
|
|
155
|
+
rejectCashSymbol(symbol, exchange, portfolio.name);
|
|
156
|
+
const ticker = await resolveTickerForCli(symbol, store, dataProvider, exchange);
|
|
157
|
+
const result = addTickerToPortfolio(ticker, portfolio.id);
|
|
158
|
+
// Name the listing that was stored: SAN:EPA is not the SAN that a bare SAN means.
|
|
159
|
+
const saved = savedListingName(ticker);
|
|
160
|
+
const data = { changed: result.changed, ...listingFields(saved), portfolio: portfolio.name };
|
|
161
|
+
if (!result.changed) {
|
|
162
|
+
ctx.printResult({ data }, { text: () => cliStyles.warning(`${saved.label} is already in "${portfolio.name}".`) });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
await store.saveTicker(result.ticker);
|
|
166
|
+
ctx.printResult({ data }, { text: () => cliStyles.success(`Added ${saved.label} to "${portfolio.name}".`) });
|
|
167
|
+
} catch (error) {
|
|
168
|
+
failPortfolioCommand(ctx, error, `Failed to add ${symbol} to "${portfolio.name}".`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function addToPortfolioCommand(args: string[], file: string | undefined, exchange: string | undefined, ctx: CliCommandContext) {
|
|
173
|
+
await withMarketData(ctx, async (market) => {
|
|
174
|
+
const { portfolio, rest } = requirePortfolioArgs(market.config, args, ADD_USAGE, ctx);
|
|
175
|
+
const list = await requireSymbolList(ctx, rest, file, ADD_USAGE);
|
|
176
|
+
if (list.single) {
|
|
177
|
+
await addTickerToPortfolioCommand(portfolio, list.single, exchange, ctx, market);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const rows = await addSymbols({
|
|
181
|
+
symbols: list.symbols,
|
|
182
|
+
exchange,
|
|
183
|
+
store: market.store,
|
|
184
|
+
dataProvider: market.dataProvider,
|
|
185
|
+
reject: cashRefusal(portfolio, exchange),
|
|
186
|
+
onRetry: retryNotice(ctx),
|
|
187
|
+
retry: (key) => `gloomberb portfolio add ${/\s/.test(portfolio.name) ? `"${portfolio.name}"` : portfolio.name} ${key}`,
|
|
188
|
+
add: (ticker) => addTickerToPortfolio(ticker, portfolio.id),
|
|
189
|
+
});
|
|
190
|
+
printSymbolRows(ctx, rows, { verb: "add", collection: { kind: "portfolio", name: portfolio.name }, repeated: list.repeated });
|
|
135
191
|
});
|
|
136
192
|
}
|
|
137
193
|
|
|
@@ -141,40 +197,64 @@ function withoutTarget(config: AppConfig, portfolio: Portfolio, symbol: string):
|
|
|
141
197
|
return removed.length > 0 ? next : null;
|
|
142
198
|
}
|
|
143
199
|
|
|
144
|
-
async function removeTickerFromPortfolioCommand(
|
|
200
|
+
async function removeTickerFromPortfolioCommand(portfolio: Portfolio, symbol: string, exchange: string | undefined, ctx: CliCommandContext, { config, store }: ConfigContext) {
|
|
145
201
|
// SAN:EPA and SAN --exchange EPA name the stored listing, which a bare SAN may hold under another venue.
|
|
146
202
|
const listing = await requireListingArg(symbol, exchange, ctx);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
203
|
+
try {
|
|
204
|
+
const ticker = await loadSavedListing(store, listing);
|
|
205
|
+
if (!ticker) ctx.fail(`Ticker "${listing.key}" was not found in your local data.`);
|
|
206
|
+
const saved = savedListingName(ticker);
|
|
207
|
+
const result = removeTickerFromPortfolio(ticker, portfolio.id);
|
|
208
|
+
if (!result.changed) ctx.fail(`${saved.key} is not in "${portfolio.name}".`);
|
|
209
|
+
await store.saveTicker(result.ticker);
|
|
210
|
+
const nextConfig = withoutTarget(config, portfolio, ticker.metadata.ticker);
|
|
211
|
+
if (nextConfig) await saveConfig(nextConfig);
|
|
212
|
+
ctx.printResult({
|
|
213
|
+
data: {
|
|
214
|
+
changed: true,
|
|
215
|
+
...listingFields(saved),
|
|
216
|
+
portfolio: portfolio.name,
|
|
217
|
+
removedPositions: result.removedPositionCount,
|
|
218
|
+
removedTarget: nextConfig != null,
|
|
219
|
+
},
|
|
220
|
+
}, {
|
|
221
|
+
text: () => [
|
|
222
|
+
cliStyles.success(`Removed ${saved.label} from "${portfolio.name}".`),
|
|
223
|
+
renderStats([
|
|
224
|
+
["Removed Positions", String(result.removedPositionCount)],
|
|
225
|
+
...(nextConfig ? [["Removed Target", "yes"] as [string, string]] : []),
|
|
226
|
+
]),
|
|
227
|
+
].join("\n"),
|
|
228
|
+
});
|
|
229
|
+
} catch (error) {
|
|
230
|
+
failPortfolioCommand(ctx, error, `Failed to remove ${symbol} from "${portfolio.name}".`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function removeFromPortfolioCommand(args: string[], file: string | undefined, exchange: string | undefined, ctx: CliCommandContext) {
|
|
235
|
+
await withConfigData(ctx, async (context) => {
|
|
236
|
+
const { portfolio, rest } = requirePortfolioArgs(context.config, args, REMOVE_USAGE, ctx);
|
|
237
|
+
const list = await requireSymbolList(ctx, rest, file, REMOVE_USAGE);
|
|
238
|
+
if (list.single) {
|
|
239
|
+
await removeTickerFromPortfolioCommand(portfolio, list.single, exchange, ctx, context);
|
|
240
|
+
return;
|
|
177
241
|
}
|
|
242
|
+
// Targets go with their holdings, all in one config write.
|
|
243
|
+
let nextConfig = context.config;
|
|
244
|
+
const rows = await removeSymbols({
|
|
245
|
+
symbols: list.symbols,
|
|
246
|
+
exchange,
|
|
247
|
+
store: context.store,
|
|
248
|
+
reject: cashRefusal(portfolio, exchange),
|
|
249
|
+
remove: (ticker) => {
|
|
250
|
+
const result = removeTickerFromPortfolio(ticker, portfolio.id);
|
|
251
|
+
const withoutTargets = result.changed ? withoutTarget(nextConfig, portfolio, ticker.metadata.ticker) : null;
|
|
252
|
+
if (withoutTargets) nextConfig = withoutTargets;
|
|
253
|
+
return { ...result, extra: { removedPositions: result.removedPositionCount, removedTarget: withoutTargets != null } };
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
if (nextConfig !== context.config) await saveConfig(nextConfig);
|
|
257
|
+
printSymbolRows(ctx, rows, { verb: "remove", collection: { kind: "portfolio", name: portfolio.name }, repeated: list.repeated });
|
|
178
258
|
});
|
|
179
259
|
}
|
|
180
260
|
|
|
@@ -204,12 +284,19 @@ async function setPositionCommand(
|
|
|
204
284
|
await store.saveTicker(result.ticker);
|
|
205
285
|
const adopted = firstPosition ? adoptFirstPositionCurrency(config, portfolio.id, currency) : null;
|
|
206
286
|
if (adopted) await saveConfig(adopted);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
[
|
|
212
|
-
|
|
287
|
+
const saved = savedListingName(result.ticker);
|
|
288
|
+
ctx.printResult({
|
|
289
|
+
data: { changed: true, ...listingFields(saved), portfolio: portfolio.name, shares, avgCost, currency },
|
|
290
|
+
}, {
|
|
291
|
+
text: () => [
|
|
292
|
+
cliStyles.success(`Set position for ${saved.label} in "${portfolio.name}".`),
|
|
293
|
+
renderStats([
|
|
294
|
+
["Shares", formatMarketQuantity(shares, { assetCategory: result.ticker.metadata.assetCategory })],
|
|
295
|
+
["Average Cost", formatMarketCostWithCurrency(avgCost, currency, { assetCategory: result.ticker.metadata.assetCategory })],
|
|
296
|
+
["Currency", currency],
|
|
297
|
+
]),
|
|
298
|
+
].join("\n"),
|
|
299
|
+
});
|
|
213
300
|
} catch (error) {
|
|
214
301
|
failPortfolioCommand(ctx, error, `Failed to set position for ${symbol} in "${portfolioName}".`);
|
|
215
302
|
}
|
|
@@ -275,7 +362,8 @@ async function clearCashCommand(name: string, ctx: CliCommandContext) {
|
|
|
275
362
|
});
|
|
276
363
|
}
|
|
277
364
|
|
|
278
|
-
|
|
365
|
+
/** The note under a target change when the targets do not add up to the whole portfolio, else null. */
|
|
366
|
+
function targetSumNote(config: AppConfig, portfolioId: string, tickers: readonly TickerRecord[]): string | null {
|
|
279
367
|
const portfolio = config.portfolios.find((entry) => entry.id === portfolioId);
|
|
280
368
|
const listed = new Set([CASH_SYMBOL, ...tickers.filter((ticker) => ticker.metadata.portfolios.includes(portfolioId)).map((ticker) => ticker.metadata.ticker)]);
|
|
281
369
|
let sum: number | null = null;
|
|
@@ -283,24 +371,34 @@ function printTargetSumNote(config: AppConfig, portfolioId: string, tickers: rea
|
|
|
283
371
|
if (listed.has(symbol)) sum = (sum ?? 0) + weight;
|
|
284
372
|
}
|
|
285
373
|
const note = describeTargetSum(sum);
|
|
286
|
-
|
|
374
|
+
return note ? cliStyles.muted(note) : null;
|
|
287
375
|
}
|
|
288
376
|
|
|
289
|
-
/**
|
|
377
|
+
/**
|
|
378
|
+
* The portfolio's own row for a listing, without a search when it is already
|
|
379
|
+
* listed. A named exchange (SAN:EPA, or SAN --exchange EPA) matches only a row
|
|
380
|
+
* on that venue, whatever key the row is saved under: a bare SAN row is one
|
|
381
|
+
* listing, Paris or New York, never both. A bare SAN takes the row saved under
|
|
382
|
+
* that key, else any row of the symbol.
|
|
383
|
+
*/
|
|
290
384
|
async function findListedTicker(store: TickerRepository, portfolio: Portfolio, symbol: string, exchange?: string): Promise<TickerRecord | null> {
|
|
291
385
|
const listing = parseListingArg(symbol, exchange);
|
|
292
|
-
const typed = symbol.trim().toUpperCase();
|
|
293
386
|
const listed = (await store.loadAllTickers()).filter((ticker) => ticker.metadata.portfolios.includes(portfolio.id));
|
|
387
|
+
const savedAs = (ticker: TickerRecord, key: string) => ticker.metadata.ticker.toUpperCase() === key;
|
|
388
|
+
if (!listing.exchange) {
|
|
389
|
+
const sameSymbol = listed.filter((ticker) => parsePublicTickerKey(ticker.metadata.ticker).symbol === listing.symbol);
|
|
390
|
+
return sameSymbol.find((ticker) => savedAs(ticker, listing.symbol)) ?? sameSymbol[0] ?? null;
|
|
391
|
+
}
|
|
392
|
+
// 7203:TSE is the row on any venue TSE names.
|
|
393
|
+
const keys = listingKeys(listing);
|
|
394
|
+
const onVenue = listed.filter((ticker) => keys.includes(canonicalTickerKey(ticker.metadata.ticker, ticker.metadata.exchange)));
|
|
294
395
|
// The key as saved (VTI:XMEX), else the same listing under another spelling of its venue (VTI:BMV).
|
|
295
|
-
return
|
|
296
|
-
?? listed.find((ticker) => {
|
|
297
|
-
const saved = parsePublicTickerKey(ticker.metadata.ticker);
|
|
298
|
-
return saved.symbol === listing.symbol
|
|
299
|
-
&& (!listing.exchange || canonicalExchange(saved.exchange ?? ticker.metadata.exchange) === listing.exchange);
|
|
300
|
-
})
|
|
301
|
-
?? null;
|
|
396
|
+
return onVenue.find((ticker) => keys.some((key) => savedAs(ticker, key))) ?? onVenue[0] ?? null;
|
|
302
397
|
}
|
|
303
398
|
|
|
399
|
+
/** What a target command reports for the cash line, in the fields a listing has. */
|
|
400
|
+
const CASH_LISTING = { key: CASH_SYMBOL, symbol: CASH_SYMBOL, exchange: "", name: null };
|
|
401
|
+
|
|
304
402
|
async function setTargetCommand(rest: string[], exchange: string | undefined, ctx: CliCommandContext) {
|
|
305
403
|
const rawWeight = rest.at(-1);
|
|
306
404
|
const symbol = rest.at(-2);
|
|
@@ -313,8 +411,12 @@ async function setTargetCommand(rest: string[], exchange: string | undefined, ct
|
|
|
313
411
|
if (isCashArgument(symbol, exchange)) {
|
|
314
412
|
const next = setPortfolioTargetWeight(config, portfolio.id, CASH_SYMBOL, weight);
|
|
315
413
|
await saveConfig(next);
|
|
316
|
-
|
|
317
|
-
|
|
414
|
+
const note = targetSumNote(next, portfolio.id, await store.loadAllTickers());
|
|
415
|
+
ctx.printResult({
|
|
416
|
+
data: { changed: true, ...listingFields(CASH_LISTING), portfolio: portfolio.name, targetWeight: weight },
|
|
417
|
+
}, {
|
|
418
|
+
text: () => [cliStyles.success(`Set the cash target in "${portfolio.name}" to ${formatAllocationWeight(weight)}.`), note].filter(Boolean).join("\n"),
|
|
419
|
+
});
|
|
318
420
|
return;
|
|
319
421
|
}
|
|
320
422
|
let ticker = await findListedTicker(store, portfolio, symbol, exchange);
|
|
@@ -324,7 +426,7 @@ async function setTargetCommand(rest: string[], exchange: string | undefined, ct
|
|
|
324
426
|
if (!resolved.metadata.portfolios.includes(portfolio.id)) {
|
|
325
427
|
if (!isManualPortfolio(portfolio)) {
|
|
326
428
|
throw new PortfolioCliError(
|
|
327
|
-
`${
|
|
429
|
+
`${savedListingName(resolved).label} is not in "${portfolio.name}".`,
|
|
328
430
|
"A broker portfolio lists what the broker holds; set targets on its holdings.",
|
|
329
431
|
);
|
|
330
432
|
}
|
|
@@ -338,9 +440,17 @@ async function setTargetCommand(rest: string[], exchange: string | undefined, ct
|
|
|
338
440
|
}
|
|
339
441
|
const next = setPortfolioTargetWeight(config, portfolio.id, ticker.metadata.ticker, weight);
|
|
340
442
|
await saveConfig(next);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
443
|
+
const saved = savedListingName(ticker);
|
|
444
|
+
const note = targetSumNote(next, portfolio.id, await store.loadAllTickers());
|
|
445
|
+
ctx.printResult({
|
|
446
|
+
data: { changed: true, ...listingFields(saved), portfolio: portfolio.name, targetWeight: weight, added },
|
|
447
|
+
}, {
|
|
448
|
+
text: () => [
|
|
449
|
+
added ? cliStyles.success(`Added ${saved.label} to "${portfolio.name}".`) : null,
|
|
450
|
+
cliStyles.success(`Set the target for ${saved.label} in "${portfolio.name}" to ${formatAllocationWeight(weight)}.`),
|
|
451
|
+
note,
|
|
452
|
+
].filter(Boolean).join("\n"),
|
|
453
|
+
});
|
|
344
454
|
} catch (error) {
|
|
345
455
|
failPortfolioCommand(ctx, error, `Failed to set the target for ${symbol} in "${name}".`);
|
|
346
456
|
}
|
|
@@ -355,21 +465,28 @@ async function clearTargetCommand(rest: string[], exchange: string | undefined,
|
|
|
355
465
|
const whole = config.portfolios.some((entry) => [entry.id, entry.name].some((value) => value.toLowerCase() === rest.join(" ").trim().toLowerCase()));
|
|
356
466
|
const portfolio = requirePortfolio(config, whole ? rest.join(" ") : rest.slice(0, -1).join(" "));
|
|
357
467
|
const rawSymbol = whole ? undefined : rest.at(-1);
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
468
|
+
const cash = rawSymbol != null && isCashArgument(rawSymbol, exchange);
|
|
469
|
+
const listing = rawSymbol == null || cash ? null : parseListingArg(rawSymbol, exchange);
|
|
470
|
+
// The row the listing is: the portfolio's own, else any saved one; a target is kept under that row's key.
|
|
471
|
+
const ticker = listing ? await findListedTicker(store, portfolio, rawSymbol!, exchange) ?? await loadSavedListing(store, listing) : null;
|
|
472
|
+
const saved = ticker ? savedListingName(ticker) : null;
|
|
473
|
+
const symbol = cash ? CASH_SYMBOL : ticker?.metadata.ticker ?? listing?.key;
|
|
361
474
|
const { config: next, removed } = clearPortfolioTargetWeights(config, portfolio.id, symbol);
|
|
475
|
+
const fields = cash ? listingFields(CASH_LISTING) : saved ? listingFields(saved) : listing ? listingFields({ ...listing, name: null }) : {};
|
|
476
|
+
const named = saved?.label ?? listing?.key ?? CASH_SYMBOL;
|
|
477
|
+
const data = { changed: removed.length > 0, ...fields, portfolio: portfolio.name, removedTargets: removed.length };
|
|
362
478
|
if (removed.length === 0) {
|
|
363
|
-
|
|
479
|
+
ctx.printResult({ data }, { text: () => cliStyles.warning(symbol ? `"${portfolio.name}" has no target for ${named}.` : `"${portfolio.name}" has no targets.`) });
|
|
364
480
|
return;
|
|
365
481
|
}
|
|
366
482
|
await saveConfig(next);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
483
|
+
ctx.printResult({ data }, {
|
|
484
|
+
text: () => cliStyles.success(
|
|
485
|
+
symbol
|
|
486
|
+
? `Cleared the ${cash ? "cash target" : `target for ${named}`} in "${portfolio.name}".`
|
|
487
|
+
: `Cleared ${removed.length} target${removed.length === 1 ? "" : "s"} in "${portfolio.name}".`,
|
|
488
|
+
),
|
|
489
|
+
});
|
|
373
490
|
} catch (error) {
|
|
374
491
|
failPortfolioCommand(ctx, error, `Failed to clear targets in "${rest.join(" ")}".`);
|
|
375
492
|
}
|
|
@@ -405,15 +522,180 @@ async function showTargetsCommand(name: string, ctx: CliCommandContext) {
|
|
|
405
522
|
console.log("");
|
|
406
523
|
console.log(renderTable(
|
|
407
524
|
[{ header: "Ticker" }, { header: "Name" }, { header: "Target", align: "right" }],
|
|
408
|
-
|
|
525
|
+
// A saved row reads as its listing (SAN:NYSE); a target whose row is not saved keeps its key.
|
|
526
|
+
rows.map((row) => {
|
|
527
|
+
const saved = row.symbol === CASH_SYMBOL ? undefined : bySymbol.get(row.symbol);
|
|
528
|
+
return [
|
|
529
|
+
saved ? listingLabel(saved) : row.symbol,
|
|
530
|
+
row.listed ? row.name ?? "" : cliStyles.muted("not in this portfolio"),
|
|
531
|
+
formatAllocationWeight(row.targetWeight),
|
|
532
|
+
];
|
|
533
|
+
}),
|
|
409
534
|
));
|
|
410
|
-
|
|
535
|
+
const note = targetSumNote(config, portfolio.id, tickers);
|
|
536
|
+
if (note) console.log(note);
|
|
411
537
|
} catch (error) {
|
|
412
538
|
failPortfolioCommand(ctx, error, `Failed to show targets for "${name}".`);
|
|
413
539
|
}
|
|
414
540
|
});
|
|
415
541
|
}
|
|
416
542
|
|
|
543
|
+
interface ThirteenFImportOptions {
|
|
544
|
+
query: string;
|
|
545
|
+
top: number;
|
|
546
|
+
name: string | undefined;
|
|
547
|
+
notional: number;
|
|
548
|
+
replace: boolean;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** An import option's value; a flag given without one fails rather than reading as left out. */
|
|
552
|
+
function takeImportValue(args: string[], flag: string, ctx: CliCommandContext): string | undefined {
|
|
553
|
+
if (!args.some((arg) => arg === flag || arg.startsWith(`${flag}=`))) return undefined;
|
|
554
|
+
const value = takeOption(args, flag)?.trim();
|
|
555
|
+
if (!value || value.startsWith("--")) ctx.fail(`${flag} needs a value.`, IMPORT_USAGE);
|
|
556
|
+
return value;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function parseImportOptions(args: string[], ctx: CliCommandContext): ThirteenFImportOptions {
|
|
560
|
+
const query = takeImportValue(args, "--13f", ctx);
|
|
561
|
+
const top = takeImportValue(args, "--top", ctx);
|
|
562
|
+
const name = takeImportValue(args, "--name", ctx);
|
|
563
|
+
const notional = takeImportValue(args, "--notional", ctx);
|
|
564
|
+
const replace = takeFlag(args, "--replace");
|
|
565
|
+
// `portfolio import holdings.csv` is a list of symbols, which add reads.
|
|
566
|
+
const path = args.find((arg) => /\.(csv|tsv|txt)$/i.test(arg));
|
|
567
|
+
if (!query && path) {
|
|
568
|
+
ctx.fail(
|
|
569
|
+
`portfolio import reads a manager's 13F filing. To add the symbols in ${path}, run: gloomberb portfolio add <portfolio> --file ${path}`,
|
|
570
|
+
IMPORT_USAGE,
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
if (!query) ctx.fail("portfolio import needs a manager: --13f <CIK|fund name>.", IMPORT_USAGE);
|
|
574
|
+
if (args.length > 0) {
|
|
575
|
+
ctx.fail(`portfolio import takes its manager and portfolio as options; got ${args.join(" ")}.`, `Quote a name with spaces, as in --13f "Berkshire Hathaway".\n${IMPORT_USAGE}`);
|
|
576
|
+
}
|
|
577
|
+
const count = top == null ? IMPORT_DEFAULT_TOP : Number(top);
|
|
578
|
+
if (!Number.isInteger(count) || count < 1 || count > IMPORT_MAX_TOP) ctx.fail(`--top must be a whole number from 1 to ${IMPORT_MAX_TOP}.`);
|
|
579
|
+
const amount = notional == null ? IMPORT_DEFAULT_NOTIONAL : Number(notional.replace(/[,_]/g, ""));
|
|
580
|
+
if (!Number.isFinite(amount) || amount <= 0) ctx.fail("--notional must be an amount above zero, such as --notional 250000.");
|
|
581
|
+
return { query, top: count, name: name || undefined, notional: amount, replace };
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* A manual portfolio from a manager's latest 13F: its largest common-stock
|
|
586
|
+
* lines that resolve to a listing, weighted by reported value, as a notional
|
|
587
|
+
* the user can see. An existing portfolio of that name is filled only when it
|
|
588
|
+
* is empty, or replaced with --replace; never overwritten silently.
|
|
589
|
+
*/
|
|
590
|
+
async function importThirteenFCommand(options: ThirteenFImportOptions, ctx: CliCommandContext) {
|
|
591
|
+
// The manager's holdings as `fn 13F <manager>` reports them, through the 13F function of the plugins that are on.
|
|
592
|
+
const thirteenF = ctx.plugins.flatMap((plugin) => plugin.paneTemplates ?? []).find((template) => template.shortcut?.prefix === "13F")?.headless;
|
|
593
|
+
if (!thirteenF) ctx.fail("13F filings are not available: the Ownership & Insiders plugin is off.", "Turn it on with gloomberb plugin enable ownership.");
|
|
594
|
+
await withMarketData(ctx, async ({ config, store, dataProvider }) => {
|
|
595
|
+
try {
|
|
596
|
+
const report = await thirteenF.load(
|
|
597
|
+
{ rawArgument: options.query, argument: options.query, symbols: [], options: { view: "holdings", limit: IMPORT_13F_ROWS } },
|
|
598
|
+
{ marketData: dataProvider, apiClient, config, signal: new AbortController().signal },
|
|
599
|
+
);
|
|
600
|
+
const source = importSource(report.metadata);
|
|
601
|
+
const rows = "rows" in report && Array.isArray(report.rows) ? report.rows : [];
|
|
602
|
+
if (!source) throw new PortfolioCliError(`No dated 13F holdings report found for "${options.query}".`);
|
|
603
|
+
const detail = { cik: source.cik, name: source.name };
|
|
604
|
+
const name = options.name ?? `${detail.name} 13F`;
|
|
605
|
+
const existing = config.portfolios.find((entry) => [entry.id, entry.name].some((value) => value.toLowerCase() === name.toLowerCase()));
|
|
606
|
+
if (existing && !isManualPortfolio(existing)) {
|
|
607
|
+
throw new PortfolioCliError(`Portfolio "${existing.name}" is broker-managed and cannot be imported into.`, "Name another with --name.");
|
|
608
|
+
}
|
|
609
|
+
const members = existing ? (await store.loadAllTickers()).filter((ticker) => ticker.metadata.portfolios.includes(existing.id)) : [];
|
|
610
|
+
if (existing && members.length > 0 && !options.replace) {
|
|
611
|
+
throw new PortfolioCliError(
|
|
612
|
+
`Portfolio "${existing.name}" already exists with ${members.length} ticker${members.length === 1 ? "" : "s"}.`,
|
|
613
|
+
`Add --replace to replace them with this 13F, or --name to import into a new portfolio.\n${IMPORT_USAGE}`,
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// The largest lines first; a line that cannot be a position, or whose ticker does not resolve, gives way to the next.
|
|
618
|
+
const picked: Array<{ line: ThirteenFImportLine; ticker: TickerRecord }> = [];
|
|
619
|
+
const skipped: Array<{ label: string; reason: string }> = [];
|
|
620
|
+
for (const line of rankThirteenFLines(rows)) {
|
|
621
|
+
if (picked.length >= options.top) break;
|
|
622
|
+
const label = line.ticker || line.issuer;
|
|
623
|
+
if (line.skip) { skipped.push({ label, reason: line.skip }); continue; }
|
|
624
|
+
try {
|
|
625
|
+
const ticker = await resolveTickerForCli(line.ticker, store, dataProvider);
|
|
626
|
+
const same = picked.find((entry) => entry.ticker.metadata.ticker === ticker.metadata.ticker);
|
|
627
|
+
if (same) { skipped.push({ label, reason: `same listing as ${same.line.ticker}` }); continue; }
|
|
628
|
+
picked.push({ line, ticker });
|
|
629
|
+
} catch (error) {
|
|
630
|
+
skipped.push({ label, reason: `ticker did not resolve (${error instanceof Error ? error.message : String(error)})` });
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (picked.length === 0) {
|
|
634
|
+
throw new PortfolioCliError(`None of ${detail.name}'s 13F lines could be imported.`, skipped.map((entry) => `${entry.label}: ${entry.reason}`).join("\n"));
|
|
635
|
+
}
|
|
636
|
+
const reported = report.metadata?.currentReportedValue;
|
|
637
|
+
const filingValue = typeof reported === "number" && Number.isFinite(reported) ? reported : null;
|
|
638
|
+
const positions = notionalPositions(picked.map((entry) => entry.line), options.notional, filingValue);
|
|
639
|
+
|
|
640
|
+
let nextConfig = config;
|
|
641
|
+
let portfolio: Portfolio;
|
|
642
|
+
if (existing) {
|
|
643
|
+
portfolio = existing;
|
|
644
|
+
for (const member of members) {
|
|
645
|
+
const removed = removeTickerFromPortfolio(member, existing.id);
|
|
646
|
+
if (removed.changed) await store.saveTicker(removed.ticker);
|
|
647
|
+
}
|
|
648
|
+
nextConfig = clearPortfolioTargetWeights(nextConfig, existing.id).config;
|
|
649
|
+
} else {
|
|
650
|
+
const created = createManualPortfolio(nextConfig, name, "USD");
|
|
651
|
+
nextConfig = created.config;
|
|
652
|
+
portfolio = created.portfolio;
|
|
653
|
+
}
|
|
654
|
+
for (const [index, position] of positions.entries()) {
|
|
655
|
+
const resolved = picked[index]!.ticker;
|
|
656
|
+
// Reread: replacing the old positions may have saved this listing since it resolved.
|
|
657
|
+
const ticker = await store.loadTicker(resolved.metadata.ticker) ?? resolved;
|
|
658
|
+
const result = setManualPortfolioPosition(ticker, portfolio.id, { shares: position.shares, avgCost: position.avgCost, currency: "USD" });
|
|
659
|
+
await store.saveTicker(result.ticker);
|
|
660
|
+
}
|
|
661
|
+
nextConfig = adoptFirstPositionCurrency(nextConfig, portfolio.id, "USD") ?? nextConfig;
|
|
662
|
+
nextConfig = { ...nextConfig, portfolios: nextConfig.portfolios.map((entry) => entry.id === portfolio.id ? { ...entry, importedFrom: source } : entry) };
|
|
663
|
+
await saveConfig(nextConfig);
|
|
664
|
+
|
|
665
|
+
const importedShare = filingValue ? picked.reduce((sum, entry) => sum + entry.line.value, 0) / filingValue : null;
|
|
666
|
+
const action = !existing ? "created" : members.length > 0 ? "replaced" : "filled";
|
|
667
|
+
const lines = positions.map((position, index) => ({ ...position, ...listingFields(savedListingName(picked[index]!.ticker)) }));
|
|
668
|
+
ctx.printResult({
|
|
669
|
+
data: {
|
|
670
|
+
changed: true, action, portfolio: portfolio.name, portfolioId: portfolio.id, importedFrom: source,
|
|
671
|
+
notional: options.notional, currency: "USD", importedShareOfFiling: importedShare,
|
|
672
|
+
removedTickers: members.length, positions: lines, skipped,
|
|
673
|
+
},
|
|
674
|
+
}, {
|
|
675
|
+
text: () => [
|
|
676
|
+
cliStyles.success(`${action === "created" ? "Created portfolio" : action === "replaced" ? `Replaced the ${members.length} ticker${members.length === 1 ? "" : "s"} in` : "Filled the empty portfolio"} "${portfolio.name}" with the top ${positions.length} positions of ${detail.name}'s 13F (CIK ${detail.cik}).`),
|
|
677
|
+
importedFromText({ importedFrom: source }),
|
|
678
|
+
`Shares are a ${formatAllocationMoney(options.notional, "USD", { whole: true })} notional at the filing's quarter-end prices${importedShare != null ? `; these lines are ${formatAllocationWeight(importedShare * 100)} of its reported value` : ""}.`,
|
|
679
|
+
"",
|
|
680
|
+
renderTable(
|
|
681
|
+
[{ header: "Ticker" }, { header: "Name" }, { header: "Weight", align: "right" }, { header: "13F %", align: "right" }, { header: "Shares", align: "right" }, { header: "Cost", align: "right" }],
|
|
682
|
+
lines.map((line) => [line.listing, line.name ?? line.issuer, formatAllocationWeight(line.weight * 100), formatAllocationWeight(line.filingWeight == null ? null : line.filingWeight * 100), formatMarketQuantity(line.shares), formatMarketCostWithCurrency(line.avgCost, "USD")]),
|
|
683
|
+
),
|
|
684
|
+
...(skipped.length ? ["", cliStyles.warning(`Skipped: ${skipped.map((entry) => `${entry.label} (${entry.reason})`).join("; ")}`)] : []),
|
|
685
|
+
renderStats([["ID", portfolio.id]]),
|
|
686
|
+
].filter((line) => line != null).join("\n"),
|
|
687
|
+
});
|
|
688
|
+
} catch (error) {
|
|
689
|
+
failPortfolioCommand(ctx, error, `Failed to import the 13F of "${options.query}".`);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const IMPORT_FLAGS = new Set(["--13f", "--top", "--name", "--notional", "--replace"]);
|
|
695
|
+
|
|
696
|
+
/** Actions that change a portfolio: none of them previews, so --dry-run would change it anyway. */
|
|
697
|
+
const MUTATING_ACTIONS = new Set(["create", "delete", "rm", "add", "remove", "position", "cash", "import"]);
|
|
698
|
+
|
|
417
699
|
export const portfolioCliCommand: CliCommandDef = {
|
|
418
700
|
name: "portfolio",
|
|
419
701
|
description: "Show holdings, value, weights and P&L; manage manual portfolios, cash and targets",
|
|
@@ -424,31 +706,56 @@ export const portfolioCliCommand: CliCommandDef = {
|
|
|
424
706
|
"portfolio show <name>",
|
|
425
707
|
"portfolio create <name>",
|
|
426
708
|
"portfolio delete <name>",
|
|
427
|
-
"portfolio add <portfolio> <
|
|
428
|
-
"portfolio remove <portfolio> <
|
|
709
|
+
"portfolio add <portfolio> <symbols...> [--file <path>]",
|
|
710
|
+
"portfolio remove <portfolio> <symbols...> [--file <path>]",
|
|
429
711
|
"portfolio position set <portfolio> <symbol> <shares> <avg-cost> [currency]",
|
|
430
712
|
"portfolio cash set <portfolio> <amount> [currency]",
|
|
431
713
|
"portfolio cash clear <portfolio>",
|
|
432
714
|
"portfolio target set <portfolio> <symbol|CASH> <weight%>",
|
|
433
715
|
"portfolio target clear <portfolio> [symbol|CASH]",
|
|
434
716
|
"portfolio target show <portfolio>",
|
|
717
|
+
"portfolio import --13f <CIK|fund name> [--top N] [--name <portfolio>] [--notional <amount>] [--replace]",
|
|
718
|
+
],
|
|
719
|
+
options: [
|
|
720
|
+
EXCHANGE_OPTION,
|
|
721
|
+
FILE_OPTION,
|
|
722
|
+
{ flags: "--13f <CIK|name>", description: "portfolio import: the 13F manager whose latest filing to import" },
|
|
723
|
+
{ flags: "--top <n>", description: `portfolio import: how many of its largest common-stock lines (default ${IMPORT_DEFAULT_TOP}, at most ${IMPORT_MAX_TOP})` },
|
|
724
|
+
{ flags: "--name <portfolio>", description: "portfolio import: the portfolio to create or fill (default: the manager's name and 13F)" },
|
|
725
|
+
{ flags: "--notional <amount>", description: "portfolio import: the USD total the shares add up to at the filing's prices (default 100,000)" },
|
|
726
|
+
{ flags: "--replace", description: "portfolio import: replace the positions of an existing portfolio of that name" },
|
|
435
727
|
],
|
|
436
|
-
options: [EXCHANGE_OPTION],
|
|
437
728
|
examples: [
|
|
438
729
|
"portfolio show Research",
|
|
439
730
|
"portfolio add Research ASML",
|
|
440
731
|
"portfolio add Research ASML:AMS",
|
|
732
|
+
"portfolio add Research --file holdings.csv",
|
|
441
733
|
"portfolio position set Research ASML 10 800 EUR",
|
|
442
734
|
"portfolio cash set Research 25000 USD",
|
|
443
735
|
"portfolio target set Research ASML 12.5%",
|
|
444
736
|
"portfolio target set Research CASH 10",
|
|
445
737
|
"portfolio show Research --csv",
|
|
738
|
+
"portfolio import --13f 0001067983 --top 10",
|
|
446
739
|
],
|
|
740
|
+
sections: [SYMBOL_LIST_HELP],
|
|
447
741
|
},
|
|
448
742
|
execute: async (rawArgs, ctx) => {
|
|
449
743
|
const args = [...rawArgs];
|
|
450
|
-
const exchange = takeOption(args, "--exchange");
|
|
451
744
|
const action = args[0];
|
|
745
|
+
if (action === "import") {
|
|
746
|
+
if (ctx.cliOptions.dryRun) ctx.fail("portfolio import has no --dry-run; it creates or fills the portfolio when it runs.");
|
|
747
|
+
await importThirteenFCommand(parseImportOptions(args.slice(1), ctx), ctx);
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
const exchange = takeOption(args, "--exchange");
|
|
751
|
+
const hasFile = args.some((arg) => arg === "--file" || arg.startsWith("--file="));
|
|
752
|
+
const file = hasFile ? takeOption(args, "--file") ?? "" : undefined;
|
|
753
|
+
if (file != null && action !== "add" && action !== "remove") ctx.fail(`--file is an option of portfolio add and remove, not portfolio ${action ?? "list"}.`, ADD_USAGE);
|
|
754
|
+
// The import's options are declared for the command; on another action one would become part of a name or symbol.
|
|
755
|
+
const importOnly = args.find((arg) => IMPORT_FLAGS.has(arg.split("=")[0]!));
|
|
756
|
+
if (importOnly) ctx.fail(`${importOnly.split("=")[0]} is an option of portfolio import, not portfolio ${action}.`, IMPORT_USAGE);
|
|
757
|
+
const mutating = MUTATING_ACTIONS.has(action ?? "") || ((action === "target" || action === "targets") && (args[1] === "set" || args[1] === "clear"));
|
|
758
|
+
if (ctx.cliOptions.dryRun && mutating) ctx.fail(`portfolio ${action} has no --dry-run; it changes the portfolio when it runs.`);
|
|
452
759
|
|
|
453
760
|
if (!action || action === "list") {
|
|
454
761
|
await listCollections(ctx);
|
|
@@ -477,18 +784,12 @@ export const portfolioCliCommand: CliCommandDef = {
|
|
|
477
784
|
}
|
|
478
785
|
|
|
479
786
|
if (action === "add") {
|
|
480
|
-
|
|
481
|
-
const name = args.slice(1, -1).join(" ");
|
|
482
|
-
if (!name || !symbol) ctx.fail("Usage: gloomberb portfolio add <portfolio> <ticker>");
|
|
483
|
-
await addTickerToPortfolioCommand(name!, symbol!, exchange, ctx);
|
|
787
|
+
await addToPortfolioCommand(args.slice(1), file, exchange, ctx);
|
|
484
788
|
return;
|
|
485
789
|
}
|
|
486
790
|
|
|
487
791
|
if (action === "remove") {
|
|
488
|
-
|
|
489
|
-
const name = args.slice(1, -1).join(" ");
|
|
490
|
-
if (!name || !symbol) ctx.fail("Usage: gloomberb portfolio remove <portfolio> <ticker>");
|
|
491
|
-
await removeTickerFromPortfolioCommand(name!, symbol!, exchange, ctx);
|
|
792
|
+
await removeFromPortfolioCommand(args.slice(1), file, exchange, ctx);
|
|
492
793
|
return;
|
|
493
794
|
}
|
|
494
795
|
|