gloomberb 0.16.1 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +26 -8
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +2 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +37 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +2 -0
- package/src/brokers/account-cache.ts +24 -0
- package/src/cli/commands/command-utils.ts +8 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +414 -106
- package/src/cli/commands/overview.ts +77 -32
- package/src/cli/commands/ticker.ts +101 -43
- package/src/cli/desktop-pane-shot.ts +34 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +1 -0
- package/src/cli/helpers.ts +4 -8
- package/src/cli/index.ts +12 -2
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +20 -2
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +27 -20
- package/src/cli/pane-functions/headless.ts +39 -11
- package/src/cli/pane-functions/index.ts +15 -4
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +35 -7
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +7 -3
- package/src/cli/result.ts +41 -27
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/view.tsx +29 -10
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +11 -11
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +14 -3
- package/src/components/metric-treemap/heat-surface.tsx +43 -16
- package/src/components/metric-treemap/heat-tiles.ts +18 -0
- package/src/components/metric-treemap/layout.ts +2 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/range-track.tsx +10 -3
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +7 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/data/config/store/normalize.ts +17 -1
- package/src/i18n/es.ts +19 -1
- package/src/i18n/ja.ts +19 -1
- package/src/i18n/ko.ts +19 -1
- package/src/i18n/zh-cn.ts +19 -1
- package/src/i18n/zh-tw.ts +19 -1
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +78 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +2 -0
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/risk-client.ts +191 -66
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
- package/src/plugins/builtin/analytics/risk-model.ts +45 -17
- package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
- package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/headless.ts +139 -5
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +20 -3
- package/src/plugins/builtin/holders/report-header.ts +95 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +2 -0
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
- package/src/plugins/builtin/market-movers/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +20 -3
- package/src/plugins/builtin/members/headless.ts +5 -3
- package/src/plugins/builtin/members/model.ts +10 -2
- package/src/plugins/builtin/members/pane.tsx +13 -6
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +48 -3
- package/src/plugins/builtin/pe-band/headless.ts +25 -7
- package/src/plugins/builtin/pe-band/model.ts +92 -16
- package/src/plugins/builtin/pe-band/pane.tsx +33 -16
- package/src/plugins/builtin/perps/client.ts +50 -3
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +248 -47
- package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +67 -4
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
- package/src/plugins/builtin/world-venue-map/model.ts +7 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/loader.ts +13 -1
- package/src/plugins/registry/pane-settings.ts +1 -0
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/styles.css +6 -7
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +27 -3
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financials.ts +8 -7
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/theme/heat-colors.ts +266 -84
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +3 -0
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +20 -1
- package/src/types/ticker.ts +15 -0
- package/src/ui/host.tsx +14 -0
- package/src/updater/index.ts +9 -11
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +14 -0
- package/src/utils/depositary-receipt.ts +26 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { createBaseConverter } from "../../../../cli/base-converter";
|
|
2
2
|
import { withMarketData } from "../../../../cli/scoped-context";
|
|
3
|
-
import {
|
|
4
|
-
countCollectionTickers,
|
|
5
|
-
formatSignedCurrency,
|
|
6
|
-
} from "../../../../cli/helpers";
|
|
3
|
+
import { countCollectionTickers } from "../../../../cli/helpers";
|
|
7
4
|
import {
|
|
8
5
|
cliStyles,
|
|
9
6
|
colorBySign,
|
|
10
7
|
renderSection,
|
|
11
|
-
renderStats,
|
|
12
8
|
renderTable,
|
|
13
9
|
} from "../../../../utils/cli-output";
|
|
14
10
|
import { formatCompact, formatPercentRaw } from "../../../../utils/format";
|
|
@@ -24,6 +20,23 @@ import type { MarketContext } from "../../../../cli/types";
|
|
|
24
20
|
import type { Portfolio, TickerPosition, TickerRecord } from "../../../../types/ticker";
|
|
25
21
|
import { instrumentFromTicker } from "../../../../market-data/request-types";
|
|
26
22
|
import { toMarketDataContext } from "../../../../market-data/selectors";
|
|
23
|
+
import { cliFreshnessFooter } from "../../../../cli/result";
|
|
24
|
+
import { quotesFreshness } from "../../../../cli/freshness";
|
|
25
|
+
import type { BrokerAccount } from "../../../../types/trading";
|
|
26
|
+
import {
|
|
27
|
+
CASH_SYMBOL,
|
|
28
|
+
buildPortfolioAllocation,
|
|
29
|
+
describeTargetSum,
|
|
30
|
+
formatAllocationDrift,
|
|
31
|
+
formatAllocationMoney,
|
|
32
|
+
formatAllocationWeight,
|
|
33
|
+
formatTradeUnits,
|
|
34
|
+
hasTargetWeights,
|
|
35
|
+
resolvePortfolioCash,
|
|
36
|
+
type AllocationHolding,
|
|
37
|
+
type PortfolioAllocation,
|
|
38
|
+
} from "../allocation";
|
|
39
|
+
import { findCachedPortfolioAccount } from "../cached-account";
|
|
27
40
|
|
|
28
41
|
/** Money prices pad to the currency's minor unit ($337.90, not $337.9), as the ticker view does. */
|
|
29
42
|
function priceFormatOptions(quote: Parameters<typeof quoteFormatOptions>[0] & { currency?: string }, assetCategory?: string) {
|
|
@@ -141,6 +154,8 @@ interface PortfolioPositionValue {
|
|
|
141
154
|
|
|
142
155
|
export interface PortfolioValuation {
|
|
143
156
|
positions: PortfolioPositionValue[];
|
|
157
|
+
/** One per ticker, for weights and targets. */
|
|
158
|
+
holdings: AllocationHolding[];
|
|
144
159
|
totalPnl: number;
|
|
145
160
|
unavailablePnl: Set<string>;
|
|
146
161
|
unavailableCost: Set<string>;
|
|
@@ -175,6 +190,7 @@ export async function valuePortfolioPositions({
|
|
|
175
190
|
const unavailableMarketValue = new Set<string>();
|
|
176
191
|
const brokerPnlSymbols = new Set<string>();
|
|
177
192
|
const values: PortfolioPositionValue[] = [];
|
|
193
|
+
const holdings: AllocationHolding[] = [];
|
|
178
194
|
const known = (value: number | null | undefined): number | null => value != null && Number.isFinite(value) ? value : null;
|
|
179
195
|
|
|
180
196
|
for (const ticker of tickers) {
|
|
@@ -184,6 +200,9 @@ export async function valuePortfolioPositions({
|
|
|
184
200
|
const activeQuote = displayedQuote && Number.isFinite(displayedQuote.price) ? displayedQuote : null;
|
|
185
201
|
|
|
186
202
|
if (positions.length === 0) {
|
|
203
|
+
const quoteCurrency = quote?.currency || ticker.metadata.currency || baseCurrency;
|
|
204
|
+
const unitPrice = activeQuote ? known(await toBase(activeQuote.price, quoteCurrency)) : null;
|
|
205
|
+
holdings.push({ symbol: ticker.metadata.ticker, held: false, marketValue: 0, units: 0, unitPrice });
|
|
187
206
|
values.push({ ticker, quote, activeQuote, position: null, metrics: null, pnl: null,
|
|
188
207
|
row: { symbol: ticker.metadata.ticker, exchange: ticker.metadata.exchange, shares: null, avgCost: null,
|
|
189
208
|
positionCurrency: null, quotePrice: known(activeQuote?.price), quoteCurrency: quote?.currency ?? null,
|
|
@@ -191,6 +210,8 @@ export async function valuePortfolioPositions({
|
|
|
191
210
|
continue;
|
|
192
211
|
}
|
|
193
212
|
|
|
213
|
+
const holding: AllocationHolding = { symbol: ticker.metadata.ticker, held: true, marketValue: 0, units: 0, unitPrice: null };
|
|
214
|
+
holdings.push(holding);
|
|
194
215
|
for (const position of positions) {
|
|
195
216
|
const quoteCurrency = quote?.currency || ticker.metadata.currency || baseCurrency;
|
|
196
217
|
const metrics = getPortfolioPositionMetrics({ ...ticker, metadata: { ...ticker.metadata, positions: [position] } }, id, quoteCurrency, undefined, quote);
|
|
@@ -212,24 +233,72 @@ export async function valuePortfolioPositions({
|
|
|
212
233
|
if (pnl != null && Number.isFinite(pnl)) totalPnl += pnl;
|
|
213
234
|
else unavailablePnl.add(ticker.metadata.ticker);
|
|
214
235
|
const direction = metrics.totalShares < 0 ? -1 : 1;
|
|
236
|
+
const marketValue = currentValueBase == null ? null : known(direction * currentValueBase);
|
|
237
|
+
holding.marketValue = holding.marketValue == null || marketValue == null ? null : holding.marketValue + marketValue;
|
|
238
|
+
holding.units += metrics.totalShares;
|
|
239
|
+
holding.unitPrice ??= valuationQuote ? known(await toBase(valuationQuote.price, quoteCurrency)) : null;
|
|
215
240
|
values.push({ ticker, quote, activeQuote, position, metrics, pnl,
|
|
216
241
|
row: { symbol: ticker.metadata.ticker, exchange: ticker.metadata.exchange,
|
|
217
242
|
shares: metrics.totalShares, avgCost: known(position.avgCost), positionCurrency,
|
|
218
243
|
priceBasis: position.priceBasis ?? null, quantityUnit: metrics.priceBasis === "percent-of-par" ? "face" : null, quotePriceBasis: quote?.priceBasis ?? null,
|
|
219
244
|
quotePrice: known(activeQuote?.price), quoteCurrency, quoteAsOf: quote?.lastUpdated ?? null,
|
|
220
|
-
costBasis: known(direction * costBasisBase), marketValue
|
|
245
|
+
costBasis: known(direction * costBasisBase), marketValue,
|
|
221
246
|
unrealizedPnl: known(pnl), baseCurrency: currency, dateAcquired: position.dateAcquired ?? null,
|
|
222
247
|
pnlBasis: selectedPnl.basis, brokerUnrealizedPnl: known(position.unrealizedPnl), brokerPnlCurrency: positionCurrency, brokerPnlAsOf: null } });
|
|
223
248
|
}
|
|
224
249
|
}
|
|
225
250
|
|
|
226
|
-
return { positions: values, totalPnl, unavailablePnl, unavailableCost, unavailableMarketValue, brokerPnlSymbols };
|
|
251
|
+
return { positions: values, holdings, totalPnl, unavailablePnl, unavailableCost, unavailableMarketValue, brokerPnlSymbols };
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** A portfolio's cash line, as `portfolio show` and `fn PF` report it. */
|
|
255
|
+
export interface PortfolioCashReport {
|
|
256
|
+
/** In the cash's own currency. */
|
|
257
|
+
amount: number;
|
|
258
|
+
currency: string;
|
|
259
|
+
/** Recorded with `portfolio cash set`, or reported by the broker account. */
|
|
260
|
+
source: "manual" | "broker";
|
|
261
|
+
/** In the portfolio's currency; null when the rate is unavailable. */
|
|
262
|
+
value: number | null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Weights, targets and trades for a valued portfolio, with its cash: the
|
|
267
|
+
* broker account's when it reports one, else the amount entered by hand.
|
|
268
|
+
*/
|
|
269
|
+
export async function valuePortfolioAllocation({
|
|
270
|
+
valuation,
|
|
271
|
+
portfolio,
|
|
272
|
+
account,
|
|
273
|
+
toBase,
|
|
274
|
+
}: {
|
|
275
|
+
valuation: Pick<PortfolioValuation, "holdings">;
|
|
276
|
+
portfolio: Portfolio;
|
|
277
|
+
account?: BrokerAccount | null;
|
|
278
|
+
toBase: (value: number, fromCurrency: string) => Promise<number>;
|
|
279
|
+
}): Promise<{ allocation: PortfolioAllocation; cash: PortfolioCashReport | null }> {
|
|
280
|
+
const line = resolvePortfolioCash(portfolio, account);
|
|
281
|
+
const value = line && line.currency ? await toBase(line.amount, line.currency) : null;
|
|
282
|
+
const cash = line ? { amount: line.amount, currency: line.currency, source: line.source, value: value != null && Number.isFinite(value) ? value : null } : null;
|
|
283
|
+
const allocation = buildPortfolioAllocation({
|
|
284
|
+
holdings: valuation.holdings,
|
|
285
|
+
cashValue: cash ? cash.value ?? Number.NaN : null,
|
|
286
|
+
targets: portfolio.targetWeights,
|
|
287
|
+
});
|
|
288
|
+
return { allocation, cash };
|
|
227
289
|
}
|
|
228
290
|
|
|
291
|
+
/** Colors a signed figure only when its text shows a nonzero digit. */
|
|
292
|
+
function signed(text: string, value: number | null | undefined): string {
|
|
293
|
+
return /[1-9]/.test(text) ? colorBySign(text, value) : text;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const NOT_AVAILABLE = "n/a";
|
|
297
|
+
|
|
229
298
|
async function showCollectionWithMarketData(
|
|
230
299
|
name: string,
|
|
231
300
|
ctx: CliCommandContext,
|
|
232
|
-
{ config, store, dataProvider }: MarketContext,
|
|
301
|
+
{ config, store, dataProvider, persistence }: MarketContext,
|
|
233
302
|
) {
|
|
234
303
|
const tickers = (await store.loadAllTickers()).sort((left, right) =>
|
|
235
304
|
left.metadata.ticker.localeCompare(right.metadata.ticker)
|
|
@@ -254,14 +323,22 @@ async function showCollectionWithMarketData(
|
|
|
254
323
|
// A portfolio reports in its own currency, as its pane totals; a watchlist in the base currency.
|
|
255
324
|
const currency = resolvePortfolioTotalsCurrency(matchedPortfolio, config.baseCurrency);
|
|
256
325
|
const toBase = createBaseConverter(dataProvider, currency);
|
|
326
|
+
const account = matchedPortfolio ? findCachedPortfolioAccount(config, matchedPortfolio, persistence?.resources) : null;
|
|
327
|
+
const hasCash = !!resolvePortfolioCash(matchedPortfolio, account) || hasTargetWeights(matchedPortfolio);
|
|
257
328
|
|
|
258
|
-
if (filtered.length === 0 && !structured) {
|
|
329
|
+
if (filtered.length === 0 && !structured && !hasCash) {
|
|
259
330
|
console.log(cliStyles.bold(displayName));
|
|
260
331
|
console.log(cliStyles.muted("No tickers in this collection."));
|
|
261
332
|
return;
|
|
262
333
|
}
|
|
263
334
|
|
|
264
335
|
const quotes = await loadCollectionQuotes(filtered, collection, dataProvider);
|
|
336
|
+
// Worst of across the holdings' quotes, as the PORT and watchlist reports state it.
|
|
337
|
+
const broker = !!(matchedPortfolio?.brokerId || matchedPortfolio?.brokerInstanceId);
|
|
338
|
+
const freshness = quotesFreshness(quotes.values(), {
|
|
339
|
+
source: !isPortfolio ? "Local watchlist and Gloom Cloud"
|
|
340
|
+
: broker ? "Your broker account and Gloom Cloud" : "Local portfolio and Gloom Cloud",
|
|
341
|
+
});
|
|
265
342
|
|
|
266
343
|
if (!structured) {
|
|
267
344
|
console.log(cliStyles.bold(displayName + (isPortfolio ? ` (${currency})` : "")));
|
|
@@ -269,7 +346,8 @@ async function showCollectionWithMarketData(
|
|
|
269
346
|
console.log("");
|
|
270
347
|
}
|
|
271
348
|
|
|
272
|
-
if (
|
|
349
|
+
if (matchedPortfolio) {
|
|
350
|
+
const valuation = await valuePortfolioPositions({ tickers: filtered, quotes, portfolioId: id, currency, baseCurrency: config.baseCurrency, toBase });
|
|
273
351
|
const {
|
|
274
352
|
positions: valued,
|
|
275
353
|
totalPnl,
|
|
@@ -277,56 +355,169 @@ async function showCollectionWithMarketData(
|
|
|
277
355
|
unavailableCost,
|
|
278
356
|
unavailableMarketValue,
|
|
279
357
|
brokerPnlSymbols,
|
|
280
|
-
} =
|
|
281
|
-
const
|
|
282
|
-
const
|
|
358
|
+
} = valuation;
|
|
359
|
+
const { allocation, cash } = await valuePortfolioAllocation({ valuation, portfolio: matchedPortfolio, account, toBase });
|
|
360
|
+
const allocationBySymbol = new Map(allocation.rows.map((row) => [row.symbol, row]));
|
|
361
|
+
const showTargets = allocation.targetSum != null;
|
|
362
|
+
// A ticker held in several lots carries its allocation on its first row.
|
|
363
|
+
const firstRows = new Set<string>();
|
|
364
|
+
const positionsExport = valued.map((entry): Record<string, unknown> & {
|
|
365
|
+
weight: number | null; targetWeight: number | null; drift: number | null; tradeShares: number | null; tradeValue: number | null;
|
|
366
|
+
} => {
|
|
367
|
+
const symbol = entry.ticker.metadata.ticker;
|
|
368
|
+
const first = !firstRows.has(symbol);
|
|
369
|
+
firstRows.add(symbol);
|
|
370
|
+
const figures = first ? allocationBySymbol.get(symbol) : undefined;
|
|
371
|
+
return {
|
|
372
|
+
...entry.row,
|
|
373
|
+
weight: figures?.weight ?? null,
|
|
374
|
+
targetWeight: figures?.targetWeight ?? null,
|
|
375
|
+
drift: figures?.drift ?? null,
|
|
376
|
+
tradeShares: figures?.tradeUnits ?? null,
|
|
377
|
+
tradeValue: figures?.tradeValue ?? null,
|
|
378
|
+
};
|
|
379
|
+
});
|
|
380
|
+
const totalPnlValue = unavailablePnl.size > 0 ? null : totalPnl;
|
|
381
|
+
const cashExport = cash && allocation.cash ? {
|
|
382
|
+
...cash,
|
|
383
|
+
weight: allocation.cash.weight,
|
|
384
|
+
targetWeight: allocation.cash.targetWeight,
|
|
385
|
+
drift: allocation.cash.drift,
|
|
386
|
+
tradeValue: allocation.cash.tradeValue,
|
|
387
|
+
} : allocation.cash ? {
|
|
388
|
+
amount: 0, currency, source: "manual" as const, value: 0,
|
|
389
|
+
weight: allocation.cash.weight, targetWeight: allocation.cash.targetWeight,
|
|
390
|
+
drift: allocation.cash.drift, tradeValue: allocation.cash.tradeValue,
|
|
391
|
+
} : null;
|
|
392
|
+
|
|
393
|
+
const accountingBasis = "Unrealized P&L on current positions; excludes realized trades, distributions and cash flows. This is not account investment return.";
|
|
394
|
+
const manualAccounting = !matchedPortfolio.brokerId && !matchedPortfolio.brokerInstanceId
|
|
395
|
+
? "Manual holdings are snapshots. Reconcile shares and per-share cost after corporate actions using portfolio position set; cash distributions are not credited."
|
|
396
|
+
: null;
|
|
397
|
+
if (structured) {
|
|
398
|
+
// CSV and NDJSON read the cash and the total as rows; JSON keeps them in the metadata.
|
|
399
|
+
const extraRows: Record<string, unknown>[] = [
|
|
400
|
+
...(cashExport ? [{ symbol: CASH_SYMBOL, marketValue: cashExport.value, baseCurrency: currency, weight: cashExport.weight,
|
|
401
|
+
targetWeight: cashExport.targetWeight, drift: cashExport.drift, tradeShares: null, tradeValue: cashExport.tradeValue }] : []),
|
|
402
|
+
{ symbol: "TOTAL", marketValue: allocation.total, unrealizedPnl: totalPnlValue, baseCurrency: currency,
|
|
403
|
+
weight: allocation.total != null && allocation.total > 0 ? 100 : null, targetWeight: allocation.targetSum },
|
|
404
|
+
];
|
|
405
|
+
ctx.printResult({ data: positionsExport, metadata: {
|
|
406
|
+
portfolioId: id, portfolioName: displayName, baseCurrency: currency, currency,
|
|
407
|
+
total: allocation.total, cash: cashExport, targetSum: allocation.targetSum,
|
|
408
|
+
unpricedCount: allocation.unpriced.length, unpricedSymbols: allocation.unpriced,
|
|
409
|
+
totalUnrealizedPnl: totalPnlValue,
|
|
410
|
+
complete: unavailablePnl.size === 0 && unavailableCost.size === 0 && unavailableMarketValue.size === 0,
|
|
411
|
+
unavailableSymbols: [...new Set([...unavailablePnl, ...unavailableCost, ...unavailableMarketValue])],
|
|
412
|
+
unavailableCostSymbols: [...unavailableCost], brokerPnlSymbols: [...brokerPnlSymbols],
|
|
413
|
+
accountingBasis, ...(manualAccounting ? { manualAccounting } : {}),
|
|
414
|
+
}, freshness }, { rows: (data) => [...(data as Record<string, unknown>[]), ...extraRows] });
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const money = (value: number | null | undefined, options?: { signed?: boolean }) => formatAllocationMoney(value, currency, options);
|
|
419
|
+
// Values and trades in whole units keep the table inside 80 columns; prices, costs and P&L keep the minor unit.
|
|
420
|
+
const wholeMoney = (value: number | null | undefined, options?: { signed?: boolean }) => formatAllocationMoney(value, currency, { ...options, whole: true });
|
|
421
|
+
const allocationCells = (
|
|
422
|
+
figures: { weight: number | null; targetWeight: number | null; drift: number | null; tradeValue: number | null; tradeUnits?: number | null } | undefined,
|
|
423
|
+
{ unpriced, units, assetCategory }: { unpriced: boolean; units?: number; assetCategory?: string },
|
|
424
|
+
): string[] => {
|
|
425
|
+
const missing = unpriced ? NOT_AVAILABLE : "—";
|
|
426
|
+
const weight = figures?.weight != null ? formatAllocationWeight(figures.weight) : missing;
|
|
427
|
+
if (!showTargets) return [weight];
|
|
428
|
+
const target = figures?.targetWeight != null ? formatAllocationWeight(figures.targetWeight) : "—";
|
|
429
|
+
const hasTarget = figures?.targetWeight != null;
|
|
430
|
+
const drift = figures?.drift != null ? signed(formatAllocationDrift(figures.drift), figures.drift) : hasTarget ? missing : "—";
|
|
431
|
+
const trade = units == null ? "" : figures?.tradeUnits != null
|
|
432
|
+
? signed(formatTradeUnits(figures.tradeUnits, { units, assetCategory }), figures.tradeUnits)
|
|
433
|
+
: hasTarget ? missing : "—";
|
|
434
|
+
const tradeValue = figures?.tradeValue != null ? signed(wholeMoney(figures.tradeValue, { signed: true }), figures.tradeValue) : hasTarget ? missing : "—";
|
|
435
|
+
return [weight, target, drift, trade, tradeValue];
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
const rows: string[][] = valued.map(({ ticker, quote, activeQuote, position, metrics, pnl, row }, index) => {
|
|
283
439
|
const priceText = quote && activeQuote
|
|
284
440
|
? colorBySign(formatMarketPriceWithCurrency(activeQuote.price, quote.currency, priceFormatOptions(quote, ticker.metadata.assetCategory)), activeQuote.change)
|
|
285
441
|
: "—";
|
|
286
442
|
const changeText = activeQuote ? colorBySign(formatPercentRaw(activeQuote.changePercent), activeQuote.change) : "—";
|
|
287
|
-
|
|
443
|
+
const exported = positionsExport[index]!;
|
|
444
|
+
const figures = exported.weight != null || exported.targetWeight != null || exported.tradeValue != null
|
|
445
|
+
? { weight: exported.weight, targetWeight: exported.targetWeight, drift: exported.drift, tradeValue: exported.tradeValue, tradeUnits: exported.tradeShares }
|
|
446
|
+
: undefined;
|
|
447
|
+
const symbolUnits = allocationBySymbol.get(ticker.metadata.ticker)?.units ?? 0;
|
|
448
|
+
if (!position || !metrics) {
|
|
449
|
+
return [ticker.metadata.ticker, priceText, changeText, "—", "—", "—",
|
|
450
|
+
...allocationCells(figures, { unpriced: false, units: symbolUnits, assetCategory: ticker.metadata.assetCategory }), "—"];
|
|
451
|
+
}
|
|
288
452
|
const positionCurrency = metrics.positionCurrency;
|
|
453
|
+
const marketValue = row.marketValue as number | null;
|
|
454
|
+
const unpriced = marketValue == null;
|
|
289
455
|
return [
|
|
290
456
|
ticker.metadata.ticker,
|
|
291
457
|
priceText,
|
|
292
458
|
changeText,
|
|
293
459
|
formatMarketQuantity(metrics.totalShares, { assetCategory: ticker.metadata.assetCategory, multiplier: position.multiplier, priceBasis: metrics.priceBasis, quantityCurrency: positionCurrency }),
|
|
294
460
|
formatMarketCostWithCurrency(position.avgCost, positionCurrency, { assetCategory: ticker.metadata.assetCategory, multiplier: position.multiplier, priceBasis: metrics.priceBasis }),
|
|
295
|
-
|
|
461
|
+
unpriced ? NOT_AVAILABLE : wholeMoney(marketValue),
|
|
462
|
+
...allocationCells(figures, { unpriced, units: symbolUnits, assetCategory: ticker.metadata.assetCategory }),
|
|
463
|
+
pnl == null || !Number.isFinite(pnl) ? "—" : colorBySign(money(pnl, { signed: true }), pnl),
|
|
296
464
|
];
|
|
297
465
|
});
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
: null;
|
|
303
|
-
if (structured) {
|
|
304
|
-
ctx.printResult({ data: positionsExport, metadata: {
|
|
305
|
-
portfolioId: id, portfolioName: displayName, baseCurrency: currency,
|
|
306
|
-
totalUnrealizedPnl: unavailablePnl.size > 0 ? null : totalPnl,
|
|
307
|
-
complete: unavailablePnl.size === 0 && unavailableCost.size === 0 && unavailableMarketValue.size === 0,
|
|
308
|
-
unavailableSymbols: [...new Set([...unavailablePnl, ...unavailableCost, ...unavailableMarketValue])],
|
|
309
|
-
unavailableCostSymbols: [...unavailableCost], brokerPnlSymbols: [...brokerPnlSymbols],
|
|
310
|
-
accountingBasis, ...(manualAccounting ? { manualAccounting } : {}),
|
|
311
|
-
} });
|
|
312
|
-
return;
|
|
466
|
+
if (cashExport) {
|
|
467
|
+
const label = cashExport.currency && cashExport.currency !== currency ? `${CASH_SYMBOL} ${cashExport.currency}` : CASH_SYMBOL;
|
|
468
|
+
rows.push([label, "", "", "", "", cashExport.value == null ? NOT_AVAILABLE : wholeMoney(cashExport.value),
|
|
469
|
+
...allocationCells(cashExport, { unpriced: cashExport.value == null }), ""]);
|
|
313
470
|
}
|
|
471
|
+
const total = allocation.total;
|
|
472
|
+
rows.push([
|
|
473
|
+
cliStyles.bold("TOTAL"), "", "", "", "",
|
|
474
|
+
cliStyles.bold(wholeMoney(total)),
|
|
475
|
+
total != null && total > 0 ? formatAllocationWeight(100) : "—",
|
|
476
|
+
...(showTargets ? [formatAllocationWeight(allocation.targetSum), "", "", ""] : []),
|
|
477
|
+
totalPnlValue == null ? "—" : colorBySign(money(totalPnlValue, { signed: true }), totalPnlValue),
|
|
478
|
+
]);
|
|
314
479
|
|
|
480
|
+
const quantityHeader = filtered.some(ticker => ticker.metadata.assetCategory?.toUpperCase() === "BOND") || positionsExport.some(row => row.quantityUnit === "face") ? "Qty" : "Shares";
|
|
481
|
+
// A narrow terminal drops the cost, then the quote, then P&L, before any of the allocation.
|
|
315
482
|
console.log(renderTable(
|
|
316
483
|
[
|
|
317
484
|
{ header: "Ticker" },
|
|
318
|
-
{ header: "Last", align: "right" },
|
|
319
|
-
{ header: "Chg", align: "right" },
|
|
320
|
-
{ header:
|
|
321
|
-
{ header: "Avg Cost", align: "right" },
|
|
322
|
-
{ header: "
|
|
485
|
+
{ header: "Last", align: "right", optional: true, dropPriority: 1 },
|
|
486
|
+
{ header: "Chg", align: "right", optional: true, dropPriority: 2 },
|
|
487
|
+
{ header: quantityHeader, align: "right" },
|
|
488
|
+
{ header: "Avg Cost", align: "right", optional: true, dropPriority: 3 },
|
|
489
|
+
{ header: "Value", align: "right" },
|
|
490
|
+
{ header: "Weight", align: "right" },
|
|
491
|
+
...(showTargets
|
|
492
|
+
? [
|
|
493
|
+
{ header: "Target", align: "right" as const },
|
|
494
|
+
{ header: "Drift", align: "right" as const },
|
|
495
|
+
{ header: "Trade", align: "right" as const },
|
|
496
|
+
{ header: "Trade Value", align: "right" as const },
|
|
497
|
+
]
|
|
498
|
+
: []),
|
|
499
|
+
{ header: "P&L", align: "right", optional: true },
|
|
323
500
|
],
|
|
324
501
|
rows,
|
|
325
502
|
));
|
|
326
503
|
console.log("");
|
|
327
|
-
|
|
328
|
-
if (
|
|
329
|
-
|
|
504
|
+
const notes: string[] = [];
|
|
505
|
+
if (allocation.unpriced.length > 0) {
|
|
506
|
+
const count = allocation.unpriced.length;
|
|
507
|
+
notes.push(cliStyles.warning(`Total and weights exclude ${count} unpriced holding${count === 1 ? "" : "s"}: ${allocation.unpriced.join(", ")}.`));
|
|
508
|
+
}
|
|
509
|
+
if (cashExport?.source === "broker") notes.push(cliStyles.muted("Cash is the broker account's balance as of its last sync."));
|
|
510
|
+
if (cashExport && cashExport.value == null) {
|
|
511
|
+
notes.push(cliStyles.warning(cashExport.currency
|
|
512
|
+
? `No ${cashExport.currency}/${currency} rate for the cash, so the total and weights are unavailable.`
|
|
513
|
+
: "The cash's currency is unknown, so the total and weights are unavailable."));
|
|
514
|
+
}
|
|
515
|
+
const targetNote = describeTargetSum(allocation.targetSum);
|
|
516
|
+
if (targetNote) notes.push(cliStyles.muted(targetNote));
|
|
517
|
+
if (brokerPnlSymbols.size > 0) notes.push(cliStyles.muted(`P&L for ${[...brokerPnlSymbols].join(", ")} is the broker's last snapshot.`));
|
|
518
|
+
if (unavailableCost.size > 0) notes.push(cliStyles.muted(`Cost unavailable for ${[...unavailableCost].join(", ")}.`));
|
|
519
|
+
if (unavailablePnl.size > 0) notes.push(cliStyles.muted(`P&L unavailable for ${[...unavailablePnl].join(", ")}.`));
|
|
520
|
+
for (const note of notes) console.log(note);
|
|
330
521
|
} else {
|
|
331
522
|
const rows: string[][] = [];
|
|
332
523
|
for (const ticker of filtered) {
|
|
@@ -359,5 +550,5 @@ async function showCollectionWithMarketData(
|
|
|
359
550
|
rows,
|
|
360
551
|
));
|
|
361
552
|
}
|
|
362
|
-
|
|
553
|
+
if (freshness) console.log(`\n${cliFreshnessFooter(freshness)}`);
|
|
363
554
|
}
|
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
import type { AppConfig } from "../../../../types/config";
|
|
2
|
+
import type { CliCommandContext } from "../../../../types/plugin";
|
|
3
|
+
import type { TickerRecord } from "../../../../types/ticker";
|
|
4
|
+
import { parseListingArg, type SavedListingName } from "../../../../cli/listing-arg";
|
|
5
|
+
import { isUsListingExchange } from "../../../../utils/exchanges";
|
|
2
6
|
import { findPortfolio, isManualPortfolio } from "../mutations";
|
|
7
|
+
import { CASH_SYMBOL } from "../allocation";
|
|
8
|
+
|
|
9
|
+
/** A command error with a hint printed under it. */
|
|
10
|
+
export class PortfolioCliError extends Error {
|
|
11
|
+
constructor(message: string, readonly details?: string) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "PortfolioCliError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Fails the command with the error's message and hint, or the fallback for anything unexpected. */
|
|
18
|
+
export function failPortfolioCommand(ctx: CliCommandContext, error: unknown, fallback: string): never {
|
|
19
|
+
if (error instanceof Error) {
|
|
20
|
+
const details = (error as { details?: unknown }).details;
|
|
21
|
+
return ctx.fail(error.message, typeof details === "string" ? details : undefined);
|
|
22
|
+
}
|
|
23
|
+
return ctx.fail(fallback);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** What add and remove report about the listing they changed, as JSON and as the sentence's subject. */
|
|
27
|
+
export function listingFields(saved: SavedListingName) {
|
|
28
|
+
return { listing: saved.key, symbol: saved.symbol, exchange: saved.exchange || null, name: saved.name };
|
|
29
|
+
}
|
|
3
30
|
|
|
4
31
|
export function parseFiniteNumber(rawValue: string | undefined, label: string): number {
|
|
5
32
|
const value = Number(rawValue);
|
|
@@ -9,13 +36,51 @@ export function parseFiniteNumber(rawValue: string | undefined, label: string):
|
|
|
9
36
|
return value;
|
|
10
37
|
}
|
|
11
38
|
|
|
12
|
-
export function
|
|
39
|
+
export function requirePortfolio(config: AppConfig, rawName: string): NonNullable<ReturnType<typeof findPortfolio>> {
|
|
13
40
|
const portfolio = findPortfolio(config, rawName);
|
|
14
41
|
if (!portfolio) {
|
|
15
|
-
throw new
|
|
42
|
+
throw new PortfolioCliError(
|
|
43
|
+
`Portfolio "${rawName}" was not found.`,
|
|
44
|
+
config.portfolios.length > 0 ? `Portfolios: ${config.portfolios.map((entry) => entry.name).join(", ")}` : undefined,
|
|
45
|
+
);
|
|
16
46
|
}
|
|
47
|
+
return portfolio;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function requireManualPortfolio(config: AppConfig, rawName: string): NonNullable<ReturnType<typeof findPortfolio>> {
|
|
51
|
+
const portfolio = requirePortfolio(config, rawName);
|
|
17
52
|
if (!isManualPortfolio(portfolio)) {
|
|
18
53
|
throw new Error(`Portfolio "${portfolio.name}" is broker-managed and cannot be modified manually.`);
|
|
19
54
|
}
|
|
20
55
|
return portfolio;
|
|
21
56
|
}
|
|
57
|
+
|
|
58
|
+
/** Whether the argument is the bare cash line rather than a listing (`CASH:NASDAQ` is a stock). */
|
|
59
|
+
export function isCashArgument(symbol: string, exchange?: string): boolean {
|
|
60
|
+
const listing = parseListingArg(symbol, exchange);
|
|
61
|
+
return listing.symbol === CASH_SYMBOL && !listing.exchange;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Bare `CASH` would resolve to a company that trades under that symbol and
|
|
66
|
+
* value the cash as its shares. Cash has its own line.
|
|
67
|
+
*/
|
|
68
|
+
export function rejectCashSymbol(symbol: string, exchange: string | undefined, portfolioName: string): void {
|
|
69
|
+
if (!isCashArgument(symbol, exchange)) return;
|
|
70
|
+
throw new PortfolioCliError(
|
|
71
|
+
"CASH is the portfolio's cash line, not a ticker.",
|
|
72
|
+
`Record cash with: gloomberb portfolio cash set "${portfolioName}" <amount> [currency]. For the stock that trades as CASH, name its exchange: CASH:NASDAQ.`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** `VTI (Vanguard Total Stock Market ETF)`, with the venue and currency for a listing outside the US. */
|
|
77
|
+
export function describeTicker(ticker: TickerRecord): string {
|
|
78
|
+
const { ticker: symbol, name, exchange, currency } = ticker.metadata;
|
|
79
|
+
const foreign = !!exchange && !isUsListingExchange(exchange);
|
|
80
|
+
const details = [
|
|
81
|
+
name?.trim(),
|
|
82
|
+
foreign ? exchange : undefined,
|
|
83
|
+
foreign && currency && currency.toUpperCase() !== "USD" ? currency.toUpperCase() : undefined,
|
|
84
|
+
].filter((part): part is string => !!part);
|
|
85
|
+
return details.length > 0 ? `${symbol} (${details.join(", ")})` : symbol;
|
|
86
|
+
}
|
|
@@ -3,6 +3,8 @@ import { withConfigData, withMarketData } from "../../../../cli/scoped-context";
|
|
|
3
3
|
import { countCollectionTickers, findWatchlist } from "../../../../cli/helpers";
|
|
4
4
|
import { slugifyName } from "../../../../utils/slugify";
|
|
5
5
|
import { resolveTickerForCli } from "../../../../cli/ticker-resolution";
|
|
6
|
+
import { takeOption } from "../../../../cli/commands/command-utils";
|
|
7
|
+
import { EXCHANGE_OPTION, loadSavedListing, requireListingArg, savedListingName } from "../../../../cli/listing-arg";
|
|
6
8
|
import {
|
|
7
9
|
cliStyles,
|
|
8
10
|
renderSection,
|
|
@@ -10,9 +12,13 @@ import {
|
|
|
10
12
|
renderTable,
|
|
11
13
|
} from "../../../../utils/cli-output";
|
|
12
14
|
import type { CliCommandContext, CliCommandDef } from "../../../../types/plugin";
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
+
import {
|
|
16
|
+
addTickerToWatchlist,
|
|
17
|
+
deleteWatchlist as deleteWatchlistConfig,
|
|
18
|
+
removeTickerFromWatchlist as removeWatchlistMembership,
|
|
19
|
+
} from "../mutations";
|
|
15
20
|
import { showCollection } from "./render";
|
|
21
|
+
import { listingFields } from "./shared";
|
|
16
22
|
import { CLI_COMMAND_GROUPS } from "../../../../cli/help";
|
|
17
23
|
|
|
18
24
|
async function createWatchlist(name: string, ctx: CliCommandContext) {
|
|
@@ -52,52 +58,47 @@ async function deleteWatchlist(name: string, ctx: CliCommandContext) {
|
|
|
52
58
|
});
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
async function addTickerToWatchlistCommand(watchlistName: string, symbol: string, ctx: CliCommandContext) {
|
|
61
|
+
async function addTickerToWatchlistCommand(watchlistName: string, symbol: string, exchange: string | undefined, ctx: CliCommandContext) {
|
|
56
62
|
await withMarketData(ctx, async ({ config, store, dataProvider }) => {
|
|
57
63
|
const watchlist = findWatchlist(config, watchlistName);
|
|
58
64
|
if (!watchlist) ctx.fail(`Watchlist "${watchlistName}" was not found.`);
|
|
59
65
|
|
|
60
66
|
try {
|
|
61
|
-
const ticker = await resolveTickerForCli(symbol, store, dataProvider);
|
|
67
|
+
const ticker = await resolveTickerForCli(symbol, store, dataProvider, exchange);
|
|
62
68
|
const result = addTickerToWatchlist(ticker, watchlist.id);
|
|
69
|
+
// Name the listing that was stored: SAN:EPA is not the SAN that a bare SAN means.
|
|
70
|
+
const saved = savedListingName(ticker);
|
|
71
|
+
const data = { changed: result.changed, ...listingFields(saved), watchlist: watchlist.name };
|
|
63
72
|
if (!result.changed) {
|
|
64
|
-
|
|
73
|
+
ctx.printResult({ data }, { text: () => cliStyles.warning(`${saved.label} is already in "${watchlist.name}".`) });
|
|
65
74
|
return;
|
|
66
75
|
}
|
|
67
76
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
console.log(cliStyles.success(`Added ${nextTicker.metadata.ticker} to "${watchlist.name}".`));
|
|
71
|
-
if (nextTicker.metadata.name) {
|
|
72
|
-
console.log(renderStats([["Name", nextTicker.metadata.name]]));
|
|
73
|
-
}
|
|
77
|
+
await store.saveTicker(result.ticker);
|
|
78
|
+
ctx.printResult({ data }, { text: () => cliStyles.success(`Added ${saved.label} to "${watchlist.name}".`) });
|
|
74
79
|
} catch (error) {
|
|
75
80
|
ctx.fail(error instanceof Error ? error.message : `Failed to add ${symbol} to "${watchlist.name}".`);
|
|
76
81
|
}
|
|
77
82
|
});
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
async function removeTickerFromWatchlist(watchlistName: string, symbol: string, ctx: CliCommandContext) {
|
|
85
|
+
async function removeTickerFromWatchlist(watchlistName: string, symbol: string, exchange: string | undefined, ctx: CliCommandContext) {
|
|
86
|
+
// SAN:EPA and SAN --exchange EPA name the stored listing, which a bare SAN may hold under another venue.
|
|
87
|
+
const listing = await requireListingArg(symbol, exchange, ctx);
|
|
81
88
|
await withConfigData(ctx, async ({ config, store }) => {
|
|
82
89
|
const watchlist = findWatchlist(config, watchlistName);
|
|
83
90
|
if (!watchlist) ctx.fail(`Watchlist "${watchlistName}" was not found.`);
|
|
84
91
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
92
|
+
const ticker = await loadSavedListing(store, listing);
|
|
93
|
+
if (!ticker) ctx.fail(`Ticker "${listing.key}" was not found in your local data.`);
|
|
94
|
+
const saved = savedListingName(ticker);
|
|
95
|
+
const result = removeWatchlistMembership(ticker, watchlist.id);
|
|
96
|
+
if (!result.changed) ctx.fail(`${saved.key} is not in "${watchlist.name}".`);
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
watchlists: ticker.metadata.watchlists.filter((entry) => entry !== watchlist.id),
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
await store.saveTicker(nextTicker);
|
|
100
|
-
console.log(cliStyles.success(`Removed ${normalized} from "${watchlist.name}".`));
|
|
98
|
+
await store.saveTicker(result.ticker);
|
|
99
|
+
ctx.printResult({ data: { changed: true, ...listingFields(saved), watchlist: watchlist.name } }, {
|
|
100
|
+
text: () => cliStyles.success(`Removed ${saved.label} from "${watchlist.name}".`),
|
|
101
|
+
});
|
|
101
102
|
});
|
|
102
103
|
}
|
|
103
104
|
|
|
@@ -156,9 +157,12 @@ export const watchlistCliCommand: CliCommandDef = {
|
|
|
156
157
|
"watchlist add <watchlist> <symbol>",
|
|
157
158
|
"watchlist remove <watchlist> <symbol>",
|
|
158
159
|
],
|
|
159
|
-
|
|
160
|
+
options: [EXCHANGE_OPTION],
|
|
161
|
+
examples: ["watchlist show Growth", "watchlist create Growth", "watchlist add Growth NVDA", "watchlist add Growth SAN:EPA"],
|
|
160
162
|
},
|
|
161
|
-
execute: async (
|
|
163
|
+
execute: async (rawArgs, ctx) => {
|
|
164
|
+
const args = [...rawArgs];
|
|
165
|
+
const exchange = takeOption(args, "--exchange");
|
|
162
166
|
const action = args[0];
|
|
163
167
|
|
|
164
168
|
if (!action || action === "list") {
|
|
@@ -191,7 +195,7 @@ export const watchlistCliCommand: CliCommandDef = {
|
|
|
191
195
|
const symbol = args.at(-1);
|
|
192
196
|
const name = args.slice(1, -1).join(" ");
|
|
193
197
|
if (!name || !symbol) ctx.fail("Usage: gloomberb watchlist add <watchlist> <ticker>");
|
|
194
|
-
await addTickerToWatchlistCommand(name!, symbol!, ctx);
|
|
198
|
+
await addTickerToWatchlistCommand(name!, symbol!, exchange, ctx);
|
|
195
199
|
return;
|
|
196
200
|
}
|
|
197
201
|
|
|
@@ -199,7 +203,7 @@ export const watchlistCliCommand: CliCommandDef = {
|
|
|
199
203
|
const symbol = args.at(-1);
|
|
200
204
|
const name = args.slice(1, -1).join(" ");
|
|
201
205
|
if (!name || !symbol) ctx.fail("Usage: gloomberb watchlist remove <watchlist> <ticker>");
|
|
202
|
-
await removeTickerFromWatchlist(name!, symbol!, ctx);
|
|
206
|
+
await removeTickerFromWatchlist(name!, symbol!, exchange, ctx);
|
|
203
207
|
return;
|
|
204
208
|
}
|
|
205
209
|
|