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.
Files changed (820) hide show
  1. package/README.md +14 -91
  2. package/package.json +7 -1
  3. package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
  4. package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
  5. package/src/account/billing.ts +57 -0
  6. package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
  7. package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
  8. package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
  9. package/src/account/session.ts +16 -0
  10. package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +42 -17
  11. package/src/account/upgrade-personalization.ts +57 -0
  12. package/src/account/upgrade-tickers.ts +124 -0
  13. package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
  14. package/src/api-client/askg.ts +43 -0
  15. package/src/api-client/auth.ts +15 -0
  16. package/src/api-client/beneficial-owners.ts +4 -0
  17. package/src/api-client/chat.ts +19 -0
  18. package/src/api-client/company-kpis.ts +14 -2
  19. package/src/api-client/data.ts +58 -18
  20. package/src/api-client/earnings.ts +6 -0
  21. package/src/api-client/futures-curve.ts +56 -0
  22. package/src/api-client/index.ts +16 -1
  23. package/src/api-client/market-discovery.ts +10 -1
  24. package/src/api-client/normalizers.ts +27 -0
  25. package/src/api-client/paths.ts +95 -23
  26. package/src/api-client/request.ts +2 -1
  27. package/src/api-client/research-activity.ts +46 -10
  28. package/src/api-client/socket.ts +39 -8
  29. package/src/api-client/types.ts +74 -2
  30. package/src/api-client/upgrade-experiment.ts +90 -0
  31. package/src/api-client/yield-curves.ts +8 -0
  32. package/src/app/global-shortcuts.ts +26 -2
  33. package/src/app/keybindings/actions.ts +10 -0
  34. package/src/app/pane-runtime/index.tsx +8 -0
  35. package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
  36. package/src/app/pane-runtime/plugin-bindings.ts +65 -25
  37. package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
  38. package/src/app/pane-runtime/ticker-open-runtime.ts +25 -4
  39. package/src/app/runtime/desktop-deeplink.ts +5 -0
  40. package/src/app/star-prompt/model.ts +98 -0
  41. package/src/app/star-prompt/runtime.ts +41 -0
  42. package/src/app/star-prompt/status-line.tsx +190 -0
  43. package/src/app.tsx +13 -7
  44. package/src/architecture/core-builtin-allowlist.json +61 -0
  45. package/src/brokers/signed-in/adapter.ts +33 -2
  46. package/src/brokers/signed-in/client.ts +10 -0
  47. package/src/brokers/signed-in/sign-in-dialog.tsx +34 -14
  48. package/src/brokers/signed-in/sign-in.ts +62 -5
  49. package/src/capabilities/chart-series.ts +11 -1
  50. package/src/capabilities/registry.ts +8 -1
  51. package/src/capabilities/types.ts +2 -0
  52. package/src/cli/commands/crypto-hints.ts +19 -4
  53. package/src/cli/commands/fred-series.ts +61 -0
  54. package/src/cli/commands/market.ts +744 -181
  55. package/src/cli/commands/news-hints.ts +62 -0
  56. package/src/cli/commands/news-search.ts +53 -0
  57. package/src/cli/commands/options-chain.ts +172 -0
  58. package/src/cli/commands/options-leaps.ts +425 -0
  59. package/src/cli/commands/overview.ts +251 -40
  60. package/src/cli/commands/remote.ts +2 -1
  61. package/src/cli/commands/search.ts +109 -15
  62. package/src/cli/commands/system.ts +151 -24
  63. package/src/cli/commands/themes.ts +64 -0
  64. package/src/cli/commands/ticker.ts +149 -40
  65. package/src/cli/context.ts +45 -14
  66. package/src/cli/desktop-pane-shot.ts +150 -17
  67. package/src/cli/earnings-calendar.ts +71 -0
  68. package/src/cli/errors.ts +25 -2
  69. package/src/cli/freshness.ts +22 -8
  70. package/src/cli/fx-pair.ts +57 -0
  71. package/src/cli/glossary.ts +429 -0
  72. package/src/cli/help.ts +14 -1
  73. package/src/cli/history-rows.ts +48 -7
  74. package/src/cli/index-roots.ts +58 -0
  75. package/src/cli/index.ts +29 -12
  76. package/src/cli/known-gaps.ts +27 -0
  77. package/src/cli/listing-arg.ts +595 -26
  78. package/src/cli/not-a-ticker.ts +44 -0
  79. package/src/cli/options.ts +50 -6
  80. package/src/cli/pane-functions/access-gate.ts +5 -0
  81. package/src/cli/pane-functions/capabilities.ts +11 -4
  82. package/src/cli/pane-functions/catalog.ts +48 -7
  83. package/src/cli/pane-functions/data.ts +48 -13
  84. package/src/cli/pane-functions/discovery.ts +1 -0
  85. package/src/cli/pane-functions/dom.ts +41 -19
  86. package/src/cli/pane-functions/freshness.ts +531 -32
  87. package/src/cli/pane-functions/function-help.ts +77 -25
  88. package/src/cli/pane-functions/headless.ts +50 -21
  89. package/src/cli/pane-functions/index.ts +66 -10
  90. package/src/cli/pane-functions/market-session.ts +147 -0
  91. package/src/cli/pane-functions/options.ts +77 -25
  92. package/src/cli/pane-functions/report-notices.ts +81 -0
  93. package/src/cli/pane-functions/report.ts +19 -8
  94. package/src/cli/pane-functions/resolver.ts +53 -18
  95. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  96. package/src/cli/pane-functions/screenshot.ts +199 -30
  97. package/src/cli/registry.ts +2 -1
  98. package/src/cli/report-tables.ts +3 -0
  99. package/src/cli/result.ts +53 -13
  100. package/src/cli/row-window.ts +76 -0
  101. package/src/cli/scroll-truncation.ts +34 -0
  102. package/src/cli/staged-tickers.ts +52 -0
  103. package/src/cli/symbol-args.ts +9 -0
  104. package/src/cli/symbol-list.ts +172 -0
  105. package/src/cli/ticker-resolution.ts +223 -30
  106. package/src/cli/types.ts +5 -0
  107. package/src/components/chart/composite/axis-overlays.tsx +6 -2
  108. package/src/components/chart/composite/composite-chart.tsx +83 -10
  109. package/src/components/chart/composite/legend.tsx +88 -8
  110. package/src/components/chart/composite/panel-surface.tsx +44 -17
  111. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  112. package/src/components/chart/composite/rasterizer.ts +64 -4
  113. package/src/components/chart/composite/series-cues.ts +71 -0
  114. package/src/components/chart/composite/text-renderer.ts +16 -8
  115. package/src/components/chart/composite/types.ts +3 -0
  116. package/src/components/command-bar/commands/direct/index.ts +9 -1
  117. package/src/components/command-bar/commands/plugin/items.ts +3 -1
  118. package/src/components/command-bar/commands/registry.ts +7 -0
  119. package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
  120. package/src/components/command-bar/pane-templates/workflow.ts +5 -0
  121. package/src/components/command-bar/panel/index.tsx +11 -3
  122. package/src/components/command-bar/panel/runtime.ts +3 -0
  123. package/src/components/command-bar/panel/types.ts +2 -0
  124. package/src/components/command-bar/routes/root/command-items.ts +2 -0
  125. package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
  126. package/src/components/command-bar/routes/root/provider-search.ts +4 -3
  127. package/src/components/command-bar/routes/root/results.ts +40 -10
  128. package/src/components/command-bar/routes/root/runtime.ts +8 -0
  129. package/src/components/command-bar/routes/root/search-providers.ts +97 -14
  130. package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
  131. package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
  132. package/src/components/command-bar/surface/index.tsx +18 -4
  133. package/src/components/command-bar/theme-picker.tsx +48 -13
  134. package/src/components/command-bar/workflow/ops.ts +5 -3
  135. package/src/components/command-bar/workflow/tickers.ts +23 -4
  136. package/src/components/data-table/view.tsx +28 -9
  137. package/src/components/layout/detached-pane-shell.tsx +9 -0
  138. package/src/components/layout/floating-pane.tsx +9 -2
  139. package/src/components/layout/header.tsx +20 -5
  140. package/src/components/layout/market-summary.ts +23 -9
  141. package/src/components/layout/pane/content.tsx +40 -29
  142. package/src/components/layout/pane/cycle-order.ts +2 -11
  143. package/src/components/layout/pane/footer/index.tsx +6 -2
  144. package/src/components/layout/pane/footer/model.ts +35 -1
  145. package/src/components/layout/pane/header.tsx +26 -2
  146. package/src/components/layout/pane/index.tsx +12 -2
  147. package/src/components/layout/pane/sidebar.tsx +78 -10
  148. package/src/components/layout/pane/title.ts +1 -1
  149. package/src/components/layout/presentation.ts +22 -0
  150. package/src/components/layout/shell/active-drag.ts +21 -5
  151. package/src/components/layout/shell/drag/index.ts +43 -9
  152. package/src/components/layout/shell/drag/live.ts +87 -6
  153. package/src/components/layout/shell/drag/runtime.ts +62 -20
  154. package/src/components/layout/shell/index.tsx +71 -12
  155. package/src/components/layout/shell/layout-state.ts +5 -11
  156. package/src/components/layout/shell/menu.ts +33 -1
  157. package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
  158. package/src/components/layout/shell/pane/actions.ts +2 -1
  159. package/src/components/layout/shell/pane/layers.tsx +216 -28
  160. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  161. package/src/components/layout/shell/pane/new-layout.ts +116 -0
  162. package/src/components/layout/shell/shortcuts.ts +5 -2
  163. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
  164. package/src/components/layout/shell/visible-layout.ts +44 -1
  165. package/src/components/layout/status-bar.tsx +4 -1
  166. package/src/components/markdown-text.tsx +69 -23
  167. package/src/components/metric-treemap/heat-surface.tsx +37 -9
  168. package/src/components/metric-treemap/heat-tiles.ts +48 -17
  169. package/src/components/onboarding/account-step/form-panel.tsx +1 -1
  170. package/src/components/onboarding/account-step/index.tsx +1 -1
  171. package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
  172. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  173. package/src/components/onboarding/onboarding-frame.tsx +33 -10
  174. package/src/components/onboarding/onboarding-keyboard.ts +1 -1
  175. package/src/components/onboarding/onboarding-wizard.tsx +50 -41
  176. package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
  177. package/src/components/onboarding/pro-step-layout.ts +86 -0
  178. package/src/components/onboarding/use-onboarding-upgrade.ts +8 -4
  179. package/src/components/onboarding/wizard-account.ts +2 -2
  180. package/src/components/pane-template-wizard.tsx +9 -1
  181. package/src/components/price-selector-dialog.tsx +11 -2
  182. package/src/components/sign-in-gate.tsx +3 -3
  183. package/src/components/ticker/list-table-view.tsx +24 -1
  184. package/src/components/ui/action-row.tsx +2 -1
  185. package/src/components/ui/button.tsx +17 -1
  186. package/src/components/ui/choice-dialog.tsx +6 -4
  187. package/src/components/ui/confirm-dialog.tsx +28 -18
  188. package/src/components/ui/data-table/index.tsx +49 -0
  189. package/src/components/ui/data-table/opentui/index.tsx +37 -6
  190. package/src/components/ui/data-table/types.ts +20 -1
  191. package/src/components/ui/data-table/visible-range.ts +2 -0
  192. package/src/components/ui/dialog-actions.tsx +64 -0
  193. package/src/components/ui/display.tsx +17 -3
  194. package/src/components/ui/frame.tsx +35 -2
  195. package/src/components/ui/icon.tsx +13 -2
  196. package/src/components/ui/index.ts +1 -1
  197. package/src/components/ui/text-prompt-dialog.tsx +11 -9
  198. package/src/core/connection-health.ts +1 -1
  199. package/src/core/state/app/layout-reducer.ts +89 -3
  200. package/src/core/state/app/state.ts +8 -5
  201. package/src/core/state/app/types.ts +13 -2
  202. package/src/data/cached-query.ts +2 -0
  203. package/src/data/config/layout.ts +55 -21
  204. package/src/data/config/store/fold-panes.ts +149 -0
  205. package/src/data/config/store/migrations.ts +7 -0
  206. package/src/data/config/store/node.ts +27 -6
  207. package/src/data/config/store/normalize.ts +44 -5
  208. package/src/data/ticker-repository.ts +5 -0
  209. package/src/data/ticker-store.ts +15 -0
  210. package/src/docs/content.ts +215 -0
  211. package/src/docs/load.ts +139 -0
  212. package/src/docs/requests.ts +39 -0
  213. package/src/docs/snapshot.chunk.ts +8 -0
  214. package/src/docs/snapshot.json +7416 -0
  215. package/src/docs/topics.ts +216 -0
  216. package/src/i18n/es.ts +75 -5
  217. package/src/i18n/ja.ts +75 -5
  218. package/src/i18n/ko.ts +75 -5
  219. package/src/i18n/zh-cn.ts +75 -5
  220. package/src/i18n/zh-tw.ts +75 -5
  221. package/src/layout/desks.ts +2 -3
  222. package/src/layout/pane-layout-move.ts +264 -0
  223. package/src/layout/pane-manager/dock-tree.ts +18 -0
  224. package/src/layout/pane-manager/hidden-panes.ts +160 -0
  225. package/src/layout/pane-manager/index.ts +2 -0
  226. package/src/market-data/coordinator/chart.ts +10 -4
  227. package/src/market-data/coordinator/entries.ts +7 -1
  228. package/src/market-data/coordinator/index.ts +6 -3
  229. package/src/market-data/coordinator/quotes.ts +2 -2
  230. package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
  231. package/src/market-data/futures-contract.ts +151 -0
  232. package/src/market-data/hooks.tsx +10 -2
  233. package/src/market-data/market/format.ts +39 -21
  234. package/src/market-data/market/freshness.ts +193 -30
  235. package/src/market-data/market/status.ts +59 -23
  236. package/src/market-data/options-alternatives.ts +69 -0
  237. package/src/market-data/published-apac-sessions.ts +23 -1
  238. package/src/market-data/quotes/contributions.ts +22 -2
  239. package/src/market-data/quotes/metadata.ts +8 -9
  240. package/src/market-data/quotes/resolution.ts +2 -0
  241. package/src/market-data/quotes/screener-live-quotes.ts +61 -9
  242. package/src/market-data/result-types.ts +2 -0
  243. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  244. package/src/plugins/builtin/account-management/model.ts +2 -56
  245. package/src/plugins/builtin/account-management/navigation.ts +1 -1
  246. package/src/plugins/builtin/account-management/pane.tsx +37 -8
  247. package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
  248. package/src/plugins/builtin/alerts/cli.ts +313 -47
  249. package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
  250. package/src/plugins/builtin/alerts/events.ts +23 -2
  251. package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
  252. package/src/plugins/builtin/alerts/history.ts +2 -0
  253. package/src/plugins/builtin/alerts/index.tsx +41 -9
  254. package/src/plugins/builtin/alerts/pane.tsx +8 -0
  255. package/src/plugins/builtin/alerts/quotes.ts +3 -0
  256. package/src/plugins/builtin/alerts/research-builder.ts +8 -3
  257. package/src/plugins/builtin/alerts/research-rules.ts +18 -2
  258. package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
  259. package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
  260. package/src/plugins/builtin/alerts/scheduled.ts +254 -0
  261. package/src/plugins/builtin/alerts/targets.ts +92 -0
  262. package/src/plugins/builtin/analytics/index.tsx +4 -2
  263. package/src/plugins/builtin/analytics/risk-headless.ts +33 -13
  264. package/src/plugins/builtin/analytics/risk-math.ts +91 -27
  265. package/src/plugins/builtin/analytics/risk-model.ts +71 -12
  266. package/src/plugins/builtin/analytics/risk-pane.tsx +23 -12
  267. package/src/plugins/builtin/attention/index.tsx +2 -0
  268. package/src/plugins/builtin/attention/pane.tsx +3 -1
  269. package/src/plugins/builtin/attention/series.ts +26 -0
  270. package/src/plugins/builtin/awards/index.tsx +2 -0
  271. package/src/plugins/builtin/awards/pane.tsx +3 -1
  272. package/src/plugins/builtin/awards/series.ts +29 -0
  273. package/src/plugins/builtin/backtest/pane.tsx +1 -1
  274. package/src/plugins/builtin/bond-calculator/model.ts +2 -1
  275. package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
  276. package/src/plugins/builtin/broker-manager/index.tsx +7 -3
  277. package/src/plugins/builtin/broker-manager/model.ts +8 -0
  278. package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
  279. package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
  280. package/src/plugins/builtin/broker-manager/table.ts +5 -0
  281. package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
  282. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  283. package/src/plugins/builtin/cds/client.ts +70 -13
  284. package/src/plugins/builtin/cds/headless.ts +116 -19
  285. package/src/plugins/builtin/cds/index.tsx +3 -1
  286. package/src/plugins/builtin/cds/model.ts +193 -31
  287. package/src/plugins/builtin/cds/pane.tsx +56 -14
  288. package/src/plugins/builtin/cds/series.ts +19 -0
  289. package/src/plugins/builtin/central-bank-rates/index.tsx +2 -0
  290. package/src/plugins/builtin/central-bank-rates/series.ts +42 -0
  291. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +192 -255
  292. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
  293. package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
  294. package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
  295. package/src/plugins/builtin/chart-composer/headless.ts +8 -3
  296. package/src/plugins/builtin/chart-composer/index.tsx +9 -2
  297. package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
  298. package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
  299. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
  300. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
  301. package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
  302. package/src/plugins/builtin/chat/channels.ts +34 -36
  303. package/src/plugins/builtin/chat/command-bar.ts +138 -0
  304. package/src/plugins/builtin/chat/composer-commands.ts +21 -1
  305. package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
  306. package/src/plugins/builtin/chat/content/footer.tsx +5 -3
  307. package/src/plugins/builtin/chat/content/index.tsx +21 -1
  308. package/src/plugins/builtin/chat/content/mentions.ts +2 -1
  309. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
  310. package/src/plugins/builtin/chat/content/user-map.ts +3 -1
  311. package/src/plugins/builtin/chat/controller/index.ts +50 -0
  312. package/src/plugins/builtin/chat/conversations.ts +256 -0
  313. package/src/plugins/builtin/chat/discord-command.ts +91 -0
  314. package/src/plugins/builtin/chat/edit-window.ts +12 -6
  315. package/src/plugins/builtin/chat/ghost-user.ts +14 -0
  316. package/src/plugins/builtin/chat/index.tsx +40 -2
  317. package/src/plugins/builtin/chat/layout.ts +2 -0
  318. package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
  319. package/src/plugins/builtin/chat/message/header.tsx +24 -15
  320. package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
  321. package/src/plugins/builtin/chat/message/render-state.ts +3 -0
  322. package/src/plugins/builtin/chat/pane-requests.ts +60 -0
  323. package/src/plugins/builtin/chat/pane-state.ts +32 -2
  324. package/src/plugins/builtin/chat/pane.tsx +8 -0
  325. package/src/plugins/builtin/cloud/askg/controller.ts +223 -23
  326. package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
  327. package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
  328. package/src/plugins/builtin/cloud/askg/manifest.ts +33 -7
  329. package/src/plugins/builtin/cloud/askg/model.ts +156 -78
  330. package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
  331. package/src/plugins/builtin/cloud/askg/protocol.ts +50 -3
  332. package/src/plugins/builtin/cloud/askg/tool-display.ts +440 -0
  333. package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
  334. package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
  335. package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
  336. package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
  337. package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
  338. package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
  339. package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
  340. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +363 -0
  341. package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
  342. package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
  343. package/src/plugins/builtin/cloud/plugin.tsx +36 -1
  344. package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
  345. package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
  346. package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
  347. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +734 -0
  348. package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
  349. package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
  350. package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
  351. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +239 -0
  352. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +162 -0
  353. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +192 -0
  354. package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
  355. package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
  356. package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
  357. package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
  358. package/src/plugins/builtin/comment-letters/client.ts +1 -3
  359. package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
  360. package/src/plugins/builtin/company-attention/headless.ts +19 -5
  361. package/src/plugins/builtin/company-attention/index.tsx +2 -0
  362. package/src/plugins/builtin/company-attention/model.ts +26 -7
  363. package/src/plugins/builtin/company-attention/pane.tsx +12 -9
  364. package/src/plugins/builtin/company-attention/series.ts +52 -0
  365. package/src/plugins/builtin/company-kpis/client.ts +23 -8
  366. package/src/plugins/builtin/company-kpis/headless.ts +3 -1
  367. package/src/plugins/builtin/company-kpis/pane.tsx +19 -9
  368. package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
  369. package/src/plugins/builtin/composite-plugins.ts +116 -67
  370. package/src/plugins/builtin/cot/index.tsx +3 -1
  371. package/src/plugins/builtin/cot/model.ts +40 -11
  372. package/src/plugins/builtin/cot/series.ts +27 -0
  373. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
  374. package/src/plugins/builtin/credit-boards/index.tsx +23 -21
  375. package/src/plugins/builtin/credit-boards/model.ts +0 -1
  376. package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
  377. package/src/plugins/builtin/credit-boards/series.ts +66 -0
  378. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
  379. package/src/plugins/builtin/credit-conditions/index.tsx +2 -0
  380. package/src/plugins/builtin/credit-conditions/series.ts +26 -0
  381. package/src/plugins/builtin/credit-documents/headless.ts +31 -1
  382. package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
  383. package/src/plugins/builtin/crypto-board/headless.ts +2 -3
  384. package/src/plugins/builtin/crypto-board/index.tsx +2 -0
  385. package/src/plugins/builtin/crypto-board/model.ts +12 -0
  386. package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
  387. package/src/plugins/builtin/crypto-board/series.ts +48 -0
  388. package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
  389. package/src/plugins/builtin/debt-maturities/client.ts +37 -9
  390. package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
  391. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  392. package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
  393. package/src/plugins/builtin/debt-maturities/series.ts +45 -0
  394. package/src/plugins/builtin/dividend-yield/headless.ts +2 -2
  395. package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
  396. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  397. package/src/plugins/builtin/dividend-yield/series.ts +20 -0
  398. package/src/plugins/builtin/docs/blocks.tsx +181 -0
  399. package/src/plugins/builtin/docs/index.tsx +68 -0
  400. package/src/plugins/builtin/docs/pane.tsx +426 -0
  401. package/src/plugins/builtin/docs/targets.ts +72 -0
  402. package/src/plugins/builtin/docs/use-docs.ts +60 -0
  403. package/src/plugins/builtin/doe/index.tsx +2 -0
  404. package/src/plugins/builtin/doe/series.ts +62 -0
  405. package/src/plugins/builtin/earnings/client.ts +3 -2
  406. package/src/plugins/builtin/earnings/format.ts +1 -5
  407. package/src/plugins/builtin/earnings/headless.ts +58 -6
  408. package/src/plugins/builtin/earnings/history-model.ts +15 -1
  409. package/src/plugins/builtin/earnings/history-table.ts +13 -2
  410. package/src/plugins/builtin/earnings/history.tsx +7 -3
  411. package/src/plugins/builtin/earnings-calls/data.ts +28 -7
  412. package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
  413. package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
  414. package/src/plugins/builtin/econ/calendar-model.ts +42 -17
  415. package/src/plugins/builtin/econ/detail-view.tsx +2 -2
  416. package/src/plugins/builtin/econ/fred-catalog.ts +189 -0
  417. package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
  418. package/src/plugins/builtin/econ/index.tsx +70 -22
  419. package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
  420. package/src/plugins/builtin/econ-statistics/headless.ts +30 -5
  421. package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
  422. package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
  423. package/src/plugins/builtin/econ-statistics/view.ts +17 -0
  424. package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
  425. package/src/plugins/builtin/executives/data.ts +17 -6
  426. package/src/plugins/builtin/executives/pane.tsx +16 -7
  427. package/src/plugins/builtin/exposure/holdings.ts +1 -1
  428. package/src/plugins/builtin/exposure/pane.tsx +3 -1
  429. package/src/plugins/builtin/fear-greed/index.tsx +4 -0
  430. package/src/plugins/builtin/fear-greed/series.ts +52 -0
  431. package/src/plugins/builtin/filing-events/pane.tsx +22 -5
  432. package/src/plugins/builtin/futures/index.tsx +43 -3
  433. package/src/plugins/builtin/futures/model.ts +1 -1
  434. package/src/plugins/builtin/futures/returns.ts +1 -1
  435. package/src/plugins/builtin/futures/series.ts +13 -0
  436. package/src/plugins/builtin/futures/table.tsx +1 -1
  437. package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
  438. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  439. package/src/plugins/builtin/futures-curve/headless.ts +70 -9
  440. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  441. package/src/plugins/builtin/futures-curve/model.ts +66 -11
  442. package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
  443. package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
  444. package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
  445. package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
  446. package/src/plugins/builtin/gpu/board.tsx +13 -10
  447. package/src/plugins/builtin/gpu/changes.tsx +4 -4
  448. package/src/plugins/builtin/gpu/client.ts +19 -1
  449. package/src/plugins/builtin/gpu/equities.tsx +14 -10
  450. package/src/plugins/builtin/gpu/headless.ts +64 -27
  451. package/src/plugins/builtin/gpu/history.tsx +3 -3
  452. package/src/plugins/builtin/gpu/index.tsx +2 -0
  453. package/src/plugins/builtin/gpu/model.ts +114 -20
  454. package/src/plugins/builtin/gpu/pane.tsx +28 -12
  455. package/src/plugins/builtin/gpu/series.ts +38 -0
  456. package/src/plugins/builtin/help/function-card.tsx +25 -6
  457. package/src/plugins/builtin/help/index.tsx +18 -8
  458. package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
  459. package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
  460. package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
  461. package/src/plugins/builtin/holders/beneficial-view.tsx +62 -14
  462. package/src/plugins/builtin/holders/client.ts +22 -3
  463. package/src/plugins/builtin/holders/format.ts +18 -3
  464. package/src/plugins/builtin/holders/headless.ts +42 -134
  465. package/src/plugins/builtin/holders/pane.tsx +14 -4
  466. package/src/plugins/builtin/holders/report-header.ts +40 -5
  467. package/src/plugins/builtin/holders/report-rows.ts +240 -0
  468. package/src/plugins/builtin/insider/client.ts +35 -20
  469. package/src/plugins/builtin/insider/headless.ts +41 -11
  470. package/src/plugins/builtin/insider/index.tsx +27 -10
  471. package/src/plugins/builtin/insider/insider-data.ts +10 -0
  472. package/src/plugins/builtin/insider/issuer.ts +49 -0
  473. package/src/plugins/builtin/insider/model.ts +3 -0
  474. package/src/plugins/builtin/iv-history/charts.tsx +21 -7
  475. package/src/plugins/builtin/iv-history/client.ts +26 -6
  476. package/src/plugins/builtin/iv-history/format.ts +33 -2
  477. package/src/plugins/builtin/iv-history/headless.ts +27 -12
  478. package/src/plugins/builtin/iv-history/index.tsx +5 -3
  479. package/src/plugins/builtin/iv-history/model.ts +172 -20
  480. package/src/plugins/builtin/iv-history/pane.tsx +11 -3
  481. package/src/plugins/builtin/iv-history/screen-pane.tsx +45 -25
  482. package/src/plugins/builtin/iv-history/series.ts +29 -0
  483. package/src/plugins/builtin/jobs/headless.ts +28 -3
  484. package/src/plugins/builtin/jobs/index.tsx +3 -1
  485. package/src/plugins/builtin/jobs/pane.tsx +1 -1
  486. package/src/plugins/builtin/jobs/series.ts +19 -0
  487. package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
  488. package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
  489. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  490. package/src/plugins/builtin/kelly-sizer/pane.tsx +111 -40
  491. package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
  492. package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
  493. package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
  494. package/src/plugins/builtin/layout-manager/index.tsx +9 -1
  495. package/src/plugins/builtin/macro-day/client.ts +68 -3
  496. package/src/plugins/builtin/macro-day/headless.ts +18 -12
  497. package/src/plugins/builtin/macro-day/index.tsx +3 -0
  498. package/src/plugins/builtin/macro-day/model.ts +66 -15
  499. package/src/plugins/builtin/macro-day/pane.tsx +34 -20
  500. package/src/plugins/builtin/macro-day/release-table.ts +40 -0
  501. package/src/plugins/builtin/macro-day/releases.ts +62 -44
  502. package/src/plugins/builtin/market-heatmap/data.ts +25 -5
  503. package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
  504. package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
  505. package/src/plugins/builtin/market-heatmap/model.ts +102 -3
  506. package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
  507. package/src/plugins/builtin/market-movers/client.ts +7 -5
  508. package/src/plugins/builtin/market-movers/headless.ts +31 -4
  509. package/src/plugins/builtin/market-movers/index.tsx +11 -3
  510. package/src/plugins/builtin/market-movers/model.ts +101 -17
  511. package/src/plugins/builtin/market-movers/screener.ts +31 -0
  512. package/src/plugins/builtin/market-movers/table.ts +50 -23
  513. package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
  514. package/src/plugins/builtin/market-valuation/index.tsx +3 -3
  515. package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
  516. package/src/plugins/builtin/members/headless.ts +7 -2
  517. package/src/plugins/builtin/members/model.ts +31 -3
  518. package/src/plugins/builtin/members/pane.tsx +3 -6
  519. package/src/plugins/builtin/mna/headless.ts +15 -3
  520. package/src/plugins/builtin/money-markets/index.tsx +2 -0
  521. package/src/plugins/builtin/money-markets/series.ts +41 -0
  522. package/src/plugins/builtin/news/headless.ts +9 -2
  523. package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
  524. package/src/plugins/builtin/notes/cli.ts +12 -7
  525. package/src/plugins/builtin/openfda/client.ts +1 -1
  526. package/src/plugins/builtin/options/carry.ts +95 -0
  527. package/src/plugins/builtin/options/index.tsx +58 -5
  528. package/src/plugins/builtin/options/strike-window.ts +183 -0
  529. package/src/plugins/builtin/options/table.ts +55 -3
  530. package/src/plugins/builtin/options/types.ts +8 -1
  531. package/src/plugins/builtin/options/view.tsx +162 -13
  532. package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
  533. package/src/plugins/builtin/options-positioning/client.ts +7 -3
  534. package/src/plugins/builtin/options-positioning/headless.ts +5 -2
  535. package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
  536. package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
  537. package/src/plugins/builtin/options-scenario/client.ts +75 -18
  538. package/src/plugins/builtin/options-scenario/headless.ts +72 -24
  539. package/src/plugins/builtin/options-scenario/hedge.ts +285 -0
  540. package/src/plugins/builtin/options-scenario/index.tsx +9 -2
  541. package/src/plugins/builtin/options-scenario/model.ts +33 -0
  542. package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
  543. package/src/plugins/builtin/pe-band/model.ts +2 -2
  544. package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
  545. package/src/plugins/builtin/perps/client.ts +40 -6
  546. package/src/plugins/builtin/perps/equity-row.tsx +33 -8
  547. package/src/plugins/builtin/perps/freshness.ts +66 -0
  548. package/src/plugins/builtin/perps/headless.ts +45 -30
  549. package/src/plugins/builtin/perps/index.tsx +18 -1
  550. package/src/plugins/builtin/perps/model.ts +32 -6
  551. package/src/plugins/builtin/perps/pane.tsx +76 -20
  552. package/src/plugins/builtin/perps/series.ts +76 -0
  553. package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
  554. package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
  555. package/src/plugins/builtin/plugin-marketplace/pane.tsx +357 -39
  556. package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
  557. package/src/plugins/builtin/plugin-module.ts +90 -4
  558. package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
  559. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +273 -0
  560. package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
  561. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +400 -99
  562. package/src/plugins/builtin/portfolio-list/cli/render.ts +281 -43
  563. package/src/plugins/builtin/portfolio-list/cli/shared.ts +26 -16
  564. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -47
  565. package/src/plugins/builtin/portfolio-list/column-values.ts +1 -1
  566. package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
  567. package/src/plugins/builtin/portfolio-list/headless.ts +70 -9
  568. package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
  569. package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
  570. package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -1
  571. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +17 -1
  572. package/src/plugins/builtin/portfolio-list/summary/totals.ts +1 -1
  573. package/src/plugins/builtin/portfolio-list/table.tsx +7 -1
  574. package/src/plugins/builtin/power/client.ts +16 -0
  575. package/src/plugins/builtin/power/evidence.ts +6 -2
  576. package/src/plugins/builtin/power/headless.ts +71 -7
  577. package/src/plugins/builtin/power/index.tsx +4 -1
  578. package/src/plugins/builtin/power/model.ts +72 -1
  579. package/src/plugins/builtin/power/pane.tsx +32 -9
  580. package/src/plugins/builtin/rate-path/headless.ts +11 -3
  581. package/src/plugins/builtin/realized-vol/headless.ts +8 -0
  582. package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
  583. package/src/plugins/builtin/research/corporate-actions-pane.tsx +7 -4
  584. package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
  585. package/src/plugins/builtin/research/event-model.ts +68 -24
  586. package/src/plugins/builtin/research/events-headless.ts +2 -1
  587. package/src/plugins/builtin/research/headless.ts +2 -1
  588. package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
  589. package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
  590. package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
  591. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
  592. package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
  593. package/src/plugins/builtin/risk-factors/data.ts +23 -9
  594. package/src/plugins/builtin/risk-factors/headless.ts +5 -2
  595. package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
  596. package/src/plugins/builtin/seasonality/client.ts +15 -7
  597. package/src/plugins/builtin/seasonality/headless.ts +36 -12
  598. package/src/plugins/builtin/seasonality/index.tsx +2 -2
  599. package/src/plugins/builtin/seasonality/model.ts +119 -0
  600. package/src/plugins/builtin/seasonality/pane.tsx +108 -37
  601. package/src/plugins/builtin/sec/index.tsx +5 -5
  602. package/src/plugins/builtin/sectors/client.ts +10 -2
  603. package/src/plugins/builtin/sectors/headless.ts +35 -6
  604. package/src/plugins/builtin/sectors/index.tsx +18 -1
  605. package/src/plugins/builtin/sectors/sector-model.ts +150 -41
  606. package/src/plugins/builtin/series-inventory.ts +91 -0
  607. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
  608. package/src/plugins/builtin/shared/command-tab.ts +69 -0
  609. package/src/plugins/builtin/shared/earnings-report.ts +55 -0
  610. package/src/plugins/builtin/shared/fred-points.ts +20 -0
  611. package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
  612. package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
  613. package/src/plugins/builtin/shared/members-menu.tsx +4 -4
  614. package/src/plugins/builtin/shared/open-description.ts +29 -0
  615. package/src/plugins/builtin/shared/report-freshness.ts +59 -2
  616. package/src/plugins/builtin/shared/series-warning.ts +5 -0
  617. package/src/plugins/builtin/shared/ticker-request.ts +25 -1
  618. package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
  619. package/src/plugins/builtin/shared/volatility/options.ts +1 -46
  620. package/src/plugins/builtin/short-interest/headless.ts +1 -0
  621. package/src/plugins/builtin/short-interest/index.tsx +21 -4
  622. package/src/plugins/builtin/short-interest/series.ts +36 -0
  623. package/src/plugins/builtin/short-interest/surface.tsx +4 -4
  624. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  625. package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
  626. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  627. package/src/plugins/builtin/short-volume/index.tsx +3 -10
  628. package/src/plugins/builtin/short-volume/series.ts +23 -0
  629. package/src/plugins/builtin/social-mentions/index.tsx +2 -0
  630. package/src/plugins/builtin/social-mentions/series.ts +23 -0
  631. package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
  632. package/src/plugins/builtin/supply-chain/model.ts +1 -1
  633. package/src/plugins/builtin/supply-chain/pane.tsx +3 -1
  634. package/src/plugins/builtin/thirteenf/api.ts +1 -0
  635. package/src/plugins/builtin/thirteenf/data.ts +6 -4
  636. package/src/plugins/builtin/thirteenf/headless.ts +217 -36
  637. package/src/plugins/builtin/thirteenf/model.ts +39 -1
  638. package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
  639. package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
  640. package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
  641. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  642. package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
  643. package/src/plugins/builtin/ticker-detail/index.tsx +3 -0
  644. package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
  645. package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
  646. package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
  647. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
  648. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +48 -4
  649. package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
  650. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
  651. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
  652. package/src/plugins/builtin/time-sales/headless.ts +1 -0
  653. package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
  654. package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
  655. package/src/plugins/builtin/treasury-auctions/headless.ts +56 -6
  656. package/src/plugins/builtin/treasury-auctions/index.tsx +12 -9
  657. package/src/plugins/builtin/treasury-auctions/model.ts +205 -30
  658. package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
  659. package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
  660. package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
  661. package/src/plugins/builtin/vol-surface/client.ts +6 -2
  662. package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
  663. package/src/plugins/builtin/vol-surface/headless.ts +125 -20
  664. package/src/plugins/builtin/vol-surface/model.ts +23 -11
  665. package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
  666. package/src/plugins/builtin/vol-surface/tables.ts +124 -0
  667. package/src/plugins/builtin/volatility/index.tsx +2 -0
  668. package/src/plugins/builtin/volatility/series.ts +84 -0
  669. package/src/plugins/builtin/world-indices/client.ts +22 -4
  670. package/src/plugins/builtin/world-indices/headless.ts +54 -27
  671. package/src/plugins/builtin/world-indices/model.ts +4 -2
  672. package/src/plugins/builtin/world-indices/table.tsx +13 -2
  673. package/src/plugins/builtin/world-venue-map/geo-series.ts +27 -2
  674. package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
  675. package/src/plugins/builtin/world-venue-map/index.ts +3 -2
  676. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +8 -4
  677. package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
  678. package/src/plugins/builtin/yield-curve/chart.ts +2 -2
  679. package/src/plugins/builtin/yield-curve/curves.ts +21 -8
  680. package/src/plugins/builtin/yield-curve/headless.ts +71 -18
  681. package/src/plugins/builtin/yield-curve/index.tsx +4 -2
  682. package/src/plugins/builtin/yield-curve/series.ts +86 -0
  683. package/src/plugins/builtin-editorial.ts +126 -0
  684. package/src/plugins/catalog-backend.ts +16 -9
  685. package/src/plugins/catalog-browser.ts +129 -64
  686. package/src/plugins/catalog-manifest.ts +73 -40
  687. package/src/plugins/catalog-ui.ts +26 -6
  688. package/src/plugins/extracted-plugins.ts +7 -1
  689. package/src/plugins/ownership.ts +150 -7
  690. package/src/plugins/plugin-functions.ts +54 -0
  691. package/src/plugins/plugin-off.ts +36 -0
  692. package/src/plugins/registry/host-actions.ts +16 -0
  693. package/src/plugins/registry/index.ts +173 -28
  694. package/src/plugins/registry/plugin-state.ts +25 -1
  695. package/src/plugins/runtime/context.tsx +29 -0
  696. package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
  697. package/src/portfolio/position-value.ts +40 -0
  698. package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
  699. package/src/public/time-series.ts +17 -0
  700. package/src/react/auto-refresh.ts +13 -3
  701. package/src/react/input.ts +48 -1
  702. package/src/remote/app-host.tsx +25 -4
  703. package/src/remote/confirm-change.tsx +85 -0
  704. package/src/remote/controller-utils.ts +8 -1
  705. package/src/remote/controller.ts +126 -59
  706. package/src/remote/matching.ts +69 -0
  707. package/src/remote/pane-screenshot.ts +47 -0
  708. package/src/remote/schema.ts +63 -1
  709. package/src/remote/semantic-tree.tsx +14 -0
  710. package/src/remote/types.ts +32 -0
  711. package/src/remote/watchlist.ts +306 -0
  712. package/src/renderers/browser/main.tsx +3 -2
  713. package/src/renderers/cloudflare/worker.ts +1 -1
  714. package/src/renderers/dom/data-table/frozen-column.ts +3 -1
  715. package/src/renderers/dom/data-table/index.tsx +33 -6
  716. package/src/renderers/dom/data-table/row.tsx +27 -1
  717. package/src/renderers/dom/desktop/control-styles.ts +63 -1
  718. package/src/renderers/dom/desktop/controls.tsx +30 -23
  719. package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
  720. package/src/renderers/dom/desktop/icons.tsx +21 -0
  721. package/src/renderers/dom/desktop/query-bar.tsx +59 -32
  722. package/src/renderers/dom/dom-ui-host.tsx +3 -0
  723. package/src/renderers/dom/host/box.tsx +4 -1
  724. package/src/renderers/dom/host/chart-surface.tsx +6 -2
  725. package/src/renderers/dom/host/drag-shield.ts +17 -6
  726. package/src/renderers/dom/host/live-frame.ts +14 -2
  727. package/src/renderers/dom/host/overflow-fade.ts +14 -1
  728. package/src/renderers/dom/host/size-observer.ts +26 -0
  729. package/src/renderers/dom/host/surface-3d.tsx +7 -2
  730. package/src/renderers/dom/host/text.tsx +1 -1
  731. package/src/renderers/dom/input-host.tsx +6 -1
  732. package/src/renderers/dom/styles.css +74 -0
  733. package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
  734. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
  735. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
  736. package/src/renderers/electrobun/shared/protocol.ts +2 -0
  737. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +18 -3
  738. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +109 -5
  739. package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
  740. package/src/renderers/electrobun/view/main.tsx +6 -1
  741. package/src/renderers/opentui/input-host.tsx +6 -1
  742. package/src/renderers/opentui/start.tsx +9 -0
  743. package/src/series/capability.ts +75 -0
  744. package/src/series/csv.ts +160 -0
  745. package/src/series/files.ts +107 -0
  746. package/src/series/registry.ts +198 -0
  747. package/src/series/resolve.ts +107 -0
  748. package/src/series/standalone.ts +48 -0
  749. package/src/series/types.ts +145 -0
  750. package/src/series/validate.ts +171 -0
  751. package/src/shares/portable-layout.ts +16 -6
  752. package/src/sources/gloomberb-cloud/index.ts +26 -17
  753. package/src/sources/gloomberb-cloud/normalizers.ts +5 -1
  754. package/src/sources/history-result.ts +1 -0
  755. package/src/sources/listing-symbols.ts +14 -5
  756. package/src/sources/provider-errors.ts +88 -3
  757. package/src/sources/provider-router/batches.ts +4 -1
  758. package/src/sources/provider-router/cache.ts +4 -2
  759. package/src/sources/provider-router/cached-routes.ts +9 -5
  760. package/src/sources/provider-router/financial-routes.ts +12 -5
  761. package/src/sources/provider-router/financials.ts +55 -15
  762. package/src/sources/provider-router/history.ts +68 -34
  763. package/src/sources/provider-router/index.ts +1 -1
  764. package/src/sources/provider-router/primary.ts +23 -5
  765. package/src/sources/provider-router/search.ts +1 -0
  766. package/src/sources/sec-edgar.ts +68 -8
  767. package/src/sync/core-contributors.ts +5 -3
  768. package/src/test-support/cli-context.ts +2 -1
  769. package/src/test-support/data-provider.ts +34 -0
  770. package/src/test-support/shell-pane-keys.tsx +1 -0
  771. package/src/theme/series-colors.ts +46 -0
  772. package/src/theme/themes.ts +149 -0
  773. package/src/tickers/company-name.ts +75 -0
  774. package/src/tickers/instrument-kind.ts +25 -0
  775. package/src/tickers/open-target.ts +3 -2
  776. package/src/tickers/search/index.ts +67 -9
  777. package/src/tickers/search/ranking.ts +78 -18
  778. package/src/tickers/search/types.ts +10 -2
  779. package/src/tickers/starter-symbols.ts +8 -0
  780. package/src/tickers/us-listing.ts +34 -0
  781. package/src/time-series/hooks.ts +9 -0
  782. package/src/time-series/resolve.ts +96 -30
  783. package/src/time-series/types.ts +4 -2
  784. package/src/time-series/use-chart-resolution.ts +32 -0
  785. package/src/types/config.ts +67 -1
  786. package/src/types/data-provider.ts +5 -0
  787. package/src/types/financials.ts +52 -1
  788. package/src/types/headless.ts +72 -0
  789. package/src/types/instrument.ts +8 -0
  790. package/src/types/plugin.ts +68 -3
  791. package/src/types/price-history.ts +7 -0
  792. package/src/types/ticker.ts +14 -0
  793. package/src/ui/host.tsx +26 -4
  794. package/src/ui/index.tsx +2 -0
  795. package/src/ui/live-resize.ts +81 -0
  796. package/src/ui/live-stretch.ts +121 -0
  797. package/src/ui/measured-cells.ts +58 -0
  798. package/src/ui/pane-fill.ts +11 -0
  799. package/src/utils/basis-points.ts +17 -0
  800. package/src/utils/cli-output.ts +21 -2
  801. package/src/utils/concurrency.ts +25 -0
  802. package/src/utils/crypto-pair.ts +20 -0
  803. package/src/utils/currency-pair.ts +19 -0
  804. package/src/utils/decimal-comma.ts +19 -0
  805. package/src/utils/dom-screenshot-css.ts +265 -0
  806. package/src/utils/dom-screenshot-rasters.ts +276 -0
  807. package/src/utils/dom-screenshot.ts +437 -52
  808. package/src/utils/exchange-rate-snapshot.ts +6 -2
  809. package/src/utils/exchanges.ts +120 -1
  810. package/src/utils/format.ts +17 -3
  811. package/src/utils/fundamentals.ts +66 -0
  812. package/src/utils/futures-generic.ts +6 -12
  813. package/src/utils/fx-market-hours.ts +44 -0
  814. package/src/utils/option-expiry.ts +126 -0
  815. package/src/utils/price-history.ts +130 -40
  816. package/src/utils/rpc-timeout-error.ts +6 -2
  817. package/src/utils/sec-eps-basis.ts +178 -36
  818. package/src/utils/sec.ts +98 -40
  819. package/src/utils/throttled-fetch.ts +51 -22
  820. 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 { canonicalExchange, parsePublicTickerKey } from "../../../../utils/exchanges";
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
- async function addTickerToPortfolioCommand(portfolioName: string, symbol: string, exchange: string | undefined, ctx: CliCommandContext) {
117
- await withMarketData(ctx, async ({ config, store, dataProvider }) => {
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
- const portfolio = requireManualPortfolio(config, portfolioName);
120
- rejectCashSymbol(symbol, exchange, portfolio.name);
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
- failPortfolioCommand(ctx, error, `Failed to add ${symbol} to "${portfolioName}".`);
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(portfolioName: string, symbol: string, exchange: string | undefined, ctx: CliCommandContext) {
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
- await withConfigData(ctx, async ({ config, store }) => {
148
- try {
149
- const portfolio = requireManualPortfolio(config, portfolioName);
150
- const ticker = await loadSavedListing(store, listing);
151
- if (!ticker) ctx.fail(`Ticker "${listing.key}" was not found in your local data.`);
152
- const saved = savedListingName(ticker);
153
- const result = removeTickerFromPortfolio(ticker, portfolio.id);
154
- if (!result.changed) ctx.fail(`${saved.key} is not in "${portfolio.name}".`);
155
- await store.saveTicker(result.ticker);
156
- const nextConfig = withoutTarget(config, portfolio, ticker.metadata.ticker);
157
- if (nextConfig) await saveConfig(nextConfig);
158
- ctx.printResult({
159
- data: {
160
- changed: true,
161
- ...listingFields(saved),
162
- portfolio: portfolio.name,
163
- removedPositions: result.removedPositionCount,
164
- removedTarget: nextConfig != null,
165
- },
166
- }, {
167
- text: () => [
168
- cliStyles.success(`Removed ${saved.label} from "${portfolio.name}".`),
169
- renderStats([
170
- ["Removed Positions", String(result.removedPositionCount)],
171
- ...(nextConfig ? [["Removed Target", "yes"] as [string, string]] : []),
172
- ]),
173
- ].join("\n"),
174
- });
175
- } catch (error) {
176
- failPortfolioCommand(ctx, error, `Failed to remove ${symbol} from "${portfolioName}".`);
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
- console.log(cliStyles.success(`Set position for ${describeTicker(result.ticker)} in "${portfolio.name}".`));
208
- console.log(renderStats([
209
- ["Shares", formatMarketQuantity(shares, { assetCategory: result.ticker.metadata.assetCategory })],
210
- ["Average Cost", formatMarketCostWithCurrency(avgCost, currency, { assetCategory: result.ticker.metadata.assetCategory })],
211
- ["Currency", currency],
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
- function printTargetSumNote(config: AppConfig, portfolioId: string, tickers: readonly TickerRecord[]) {
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
- if (note) console.log(cliStyles.muted(note));
374
+ return note ? cliStyles.muted(note) : null;
287
375
  }
288
376
 
289
- /** The portfolio's own ticker for a symbol, without a search when it is already listed. */
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 listed.find((ticker) => [typed, listing.key].includes(ticker.metadata.ticker.toUpperCase()))
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
- console.log(cliStyles.success(`Set the cash target in "${portfolio.name}" to ${formatAllocationWeight(weight)}.`));
317
- printTargetSumNote(next, portfolio.id, await store.loadAllTickers());
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
- `${describeTicker(resolved)} is not in "${portfolio.name}".`,
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
- if (added) console.log(cliStyles.success(`Added ${describeTicker(ticker)} to "${portfolio.name}".`));
342
- console.log(cliStyles.success(`Set the target for ${describeTicker(ticker)} in "${portfolio.name}" to ${formatAllocationWeight(weight)}.`));
343
- printTargetSumNote(next, portfolio.id, await store.loadAllTickers());
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 symbol = rawSymbol == null ? undefined
359
- : isCashArgument(rawSymbol, exchange) ? CASH_SYMBOL
360
- : (await findListedTicker(store, portfolio, rawSymbol, exchange))?.metadata.ticker ?? parseListingArg(rawSymbol, exchange).key;
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
- console.log(cliStyles.warning(symbol ? `"${portfolio.name}" has no target for ${symbol}.` : `"${portfolio.name}" has no targets.`));
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
- if (symbol) {
368
- const ticker = symbol === CASH_SYMBOL ? null : await store.loadTicker(symbol);
369
- console.log(cliStyles.success(`Cleared the ${symbol === CASH_SYMBOL ? "cash target" : `target for ${ticker ? describeTicker(ticker) : symbol}`} in "${portfolio.name}".`));
370
- } else {
371
- console.log(cliStyles.success(`Cleared ${removed.length} target${removed.length === 1 ? "" : "s"} in "${portfolio.name}".`));
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
- rows.map((row) => [row.symbol, row.listed ? row.name ?? "" : cliStyles.muted("not in this portfolio"), formatAllocationWeight(row.targetWeight)]),
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
- printTargetSumNote(config, portfolio.id, tickers);
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> <symbol>",
428
- "portfolio remove <portfolio> <symbol>",
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
- const symbol = args.at(-1);
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
- const symbol = args.at(-1);
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