gloomberb 0.18.3 → 0.18.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 (1018) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +32 -1
  6. package/src/account/auth-model.ts +7 -3
  7. package/src/account/checkout-handoff.tsx +225 -0
  8. package/src/account/device-signin-dialog.tsx +2 -2
  9. package/src/account/device-signin.ts +2 -2
  10. package/src/account/upgrade-dialog.tsx +1 -1
  11. package/src/api-client/askg.ts +2 -2
  12. package/src/api-client/auth.ts +11 -6
  13. package/src/api-client/catalysts.ts +2 -1
  14. package/src/api-client/central-bank-rates.ts +6 -0
  15. package/src/api-client/collections.ts +5 -1
  16. package/src/api-client/cot.ts +2 -0
  17. package/src/api-client/crypto-etf-flows.ts +37 -0
  18. package/src/api-client/crypto-markets.ts +60 -0
  19. package/src/api-client/data.ts +98 -5
  20. package/src/api-client/doe.ts +15 -0
  21. package/src/api-client/equity-screener.ts +28 -0
  22. package/src/api-client/exchange-announcements.ts +38 -0
  23. package/src/api-client/fund-facts.ts +39 -0
  24. package/src/api-client/futures-curve.ts +9 -1
  25. package/src/api-client/hiring.ts +301 -0
  26. package/src/api-client/index.ts +182 -16
  27. package/src/api-client/live-scan.ts +91 -0
  28. package/src/api-client/market-discovery.ts +14 -0
  29. package/src/api-client/members.ts +18 -0
  30. package/src/api-client/mna.ts +6 -0
  31. package/src/api-client/paths.ts +18 -1
  32. package/src/api-client/request.ts +224 -26
  33. package/src/api-client/research-activity.ts +3 -10
  34. package/src/api-client/short-side-publications.ts +37 -0
  35. package/src/api-client/socket.ts +64 -4
  36. package/src/api-client/swap-curve.ts +35 -0
  37. package/src/api-client/themes.ts +7 -1
  38. package/src/api-client/types.ts +96 -2
  39. package/src/app/keybindings/index.ts +3 -0
  40. package/src/app/keybindings/labels.ts +18 -1
  41. package/src/app/keybindings/resolve.ts +14 -0
  42. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  43. package/src/app/runtime/broker-import.ts +43 -26
  44. package/src/app/runtime/desktop-deeplink.ts +5 -5
  45. package/src/app/runtime/plugin-bindings.ts +2 -2
  46. package/src/app/runtime/startup.ts +13 -0
  47. package/src/app/star-prompt/status-line.tsx +2 -2
  48. package/src/architecture/core-builtin-allowlist.json +5 -2
  49. package/src/architecture/ui-literals-allowlist.json +3 -3
  50. package/src/architecture/ui-tokens-allowlist.json +1 -1
  51. package/src/brokers/broker-portfolio-sync.ts +37 -0
  52. package/src/brokers/directory.ts +11 -0
  53. package/src/brokers/logos.ts +3 -1
  54. package/src/brokers/signed-in/adapter.ts +304 -26
  55. package/src/brokers/signed-in/client.ts +14 -2
  56. package/src/brokers/signed-in/connect.ts +10 -2
  57. package/src/brokers/sync-broker-instance.ts +9 -1
  58. package/src/capabilities/chart-series.ts +22 -6
  59. package/src/cli/bank-section.ts +1 -1
  60. package/src/cli/base-converter.ts +23 -14
  61. package/src/cli/central-bank-events.ts +1 -1
  62. package/src/cli/command-options.ts +59 -4
  63. package/src/cli/commands/api.ts +9 -6
  64. package/src/cli/commands/broker.ts +2 -2
  65. package/src/cli/commands/command-utils.ts +2 -2
  66. package/src/cli/commands/crypto-hints.ts +7 -20
  67. package/src/cli/commands/fred-series.ts +9 -2
  68. package/src/cli/commands/keybindings.ts +25 -2
  69. package/src/cli/commands/market.ts +1177 -278
  70. package/src/cli/commands/news-hints.ts +2 -2
  71. package/src/cli/commands/news-search.ts +59 -6
  72. package/src/cli/commands/options-chain.ts +59 -3
  73. package/src/cli/commands/options-leaps.ts +41 -26
  74. package/src/cli/commands/overview.ts +222 -61
  75. package/src/cli/commands/plugins.ts +9 -9
  76. package/src/cli/commands/remote.ts +13 -10
  77. package/src/cli/commands/search.ts +82 -46
  78. package/src/cli/commands/system.ts +27 -19
  79. package/src/cli/commands/themes.ts +1 -1
  80. package/src/cli/commands/ticker.ts +194 -48
  81. package/src/cli/context.ts +3 -2
  82. package/src/cli/desktop-pane-shot-view.ts +2 -2
  83. package/src/cli/desktop-pane-shot.ts +1 -1
  84. package/src/cli/earnings-calendar.ts +4 -4
  85. package/src/cli/entry.ts +18 -1
  86. package/src/cli/errors.ts +21 -3
  87. package/src/cli/exit-codes.ts +1 -1
  88. package/src/cli/export-source.ts +38 -4
  89. package/src/cli/freshness.ts +2 -8
  90. package/src/cli/fx-forward.ts +130 -0
  91. package/src/cli/fx-pair.ts +10 -9
  92. package/src/cli/glossary.ts +113 -20
  93. package/src/cli/help.ts +19 -13
  94. package/src/cli/history-export.ts +126 -0
  95. package/src/cli/history-rows.ts +226 -50
  96. package/src/cli/index-roots.ts +5 -45
  97. package/src/cli/index.ts +24 -18
  98. package/src/cli/known-gaps.ts +123 -27
  99. package/src/cli/listing-arg.ts +316 -46
  100. package/src/cli/name-entries.ts +30 -18
  101. package/src/cli/native-smoke.ts +2 -0
  102. package/src/cli/not-a-ticker.ts +19 -9
  103. package/src/cli/opentui-libc.ts +5 -0
  104. package/src/cli/options.ts +12 -0
  105. package/src/cli/pane-functions/capabilities.ts +75 -20
  106. package/src/cli/pane-functions/catalog.ts +24 -23
  107. package/src/cli/pane-functions/discovery.ts +1 -1
  108. package/src/cli/pane-functions/dom.ts +10 -7
  109. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  110. package/src/cli/pane-functions/freshness.ts +193 -30
  111. package/src/cli/pane-functions/function-help.ts +76 -30
  112. package/src/cli/pane-functions/headless.ts +59 -12
  113. package/src/cli/pane-functions/index.ts +28 -19
  114. package/src/cli/pane-functions/market-session.ts +15 -5
  115. package/src/cli/pane-functions/options.ts +22 -2
  116. package/src/cli/pane-functions/report-notices.ts +12 -4
  117. package/src/cli/pane-functions/report.ts +10 -6
  118. package/src/cli/pane-functions/resolver.ts +64 -11
  119. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  120. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  121. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  122. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  123. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  124. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  125. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  126. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  127. package/src/cli/pane-functions/shot-options.ts +8 -3
  128. package/src/cli/peso-dollar-rates.ts +79 -0
  129. package/src/cli/quote-answer.ts +45 -4
  130. package/src/cli/report-tables.ts +75 -19
  131. package/src/cli/restore-plugins.ts +42 -15
  132. package/src/cli/result.ts +164 -23
  133. package/src/cli/series-search.ts +5 -5
  134. package/src/cli/statement-filings.ts +19 -0
  135. package/src/cli/suffixed-listing-rows.ts +49 -0
  136. package/src/cli/symbol-args.ts +50 -15
  137. package/src/cli/symbol-cells.ts +120 -0
  138. package/src/cli/symbol-list.ts +198 -68
  139. package/src/cli/symbol-rows.ts +131 -25
  140. package/src/cli/ticker-resolution.ts +108 -11
  141. package/src/cli/treasury-yields.ts +5 -5
  142. package/src/cli/types.ts +2 -0
  143. package/src/cli/uncovered-instrument.ts +3 -3
  144. package/src/cli/unknown-command.ts +6 -6
  145. package/src/components/chart/composite/chart-layout.ts +131 -0
  146. package/src/components/chart/composite/composite-chart.tsx +395 -20
  147. package/src/components/chart/composite/format.ts +27 -0
  148. package/src/components/chart/composite/interactions.ts +7 -2
  149. package/src/components/chart/composite/legend.tsx +75 -3
  150. package/src/components/chart/composite/levels.ts +7 -0
  151. package/src/components/chart/composite/panel-gestures.ts +41 -0
  152. package/src/components/chart/composite/panel-labels.ts +2 -1
  153. package/src/components/chart/composite/panel-series.ts +1 -0
  154. package/src/components/chart/composite/panel-surface.tsx +314 -13
  155. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  156. package/src/components/chart/composite/range-statistics.ts +62 -0
  157. package/src/components/chart/composite/rasterizer.ts +44 -19
  158. package/src/components/chart/composite/scene.ts +20 -4
  159. package/src/components/chart/composite/series-axis-tags.tsx +16 -9
  160. package/src/components/chart/composite/text-renderer.ts +48 -21
  161. package/src/components/chart/composite/toolbar.tsx +52 -5
  162. package/src/components/chart/composite/types.ts +17 -0
  163. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  164. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  165. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  166. package/src/components/chart/composite/value-scale.ts +149 -0
  167. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  168. package/src/components/chart/core/pointer.ts +2 -0
  169. package/src/components/chart-table/index.ts +2 -0
  170. package/src/components/chart-table/read.tsx +74 -0
  171. package/src/components/command-bar/commands/collection-list.ts +41 -19
  172. package/src/components/command-bar/commands/collection.ts +9 -3
  173. package/src/components/command-bar/commands/direct/index.ts +1 -1
  174. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  175. package/src/components/command-bar/pane-templates/items.ts +59 -6
  176. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  177. package/src/components/command-bar/panel/prompt-binding.ts +0 -8
  178. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  179. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  180. package/src/components/command-bar/routes/root/results.ts +18 -4
  181. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  182. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  183. package/src/components/command-bar/routes/root/selection.ts +6 -1
  184. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  185. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  186. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  187. package/src/components/command-bar/selection-runtime.ts +50 -10
  188. package/src/components/command-bar/surface/index.tsx +24 -2
  189. package/src/components/command-bar/view-model.ts +7 -0
  190. package/src/components/command-bar/workflow/alert.ts +1 -1
  191. package/src/components/command-bar/workflow/broker.ts +2 -2
  192. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  193. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  194. package/src/components/command-bar/workflow/fields.ts +8 -2
  195. package/src/components/command-bar/workflow/ops.ts +18 -4
  196. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  197. package/src/components/command-bar/workflow/submit.ts +3 -2
  198. package/src/components/command-bar/workflow/tickers.ts +5 -1
  199. package/src/components/company-logo.tsx +39 -0
  200. package/src/components/data-table/sections.ts +4 -2
  201. package/src/components/form-modal/confirm.tsx +2 -1
  202. package/src/components/form-modal/request.ts +5 -0
  203. package/src/components/form-modal/routes.ts +4 -1
  204. package/src/components/index.ts +12 -6
  205. package/src/components/layout/header.tsx +33 -46
  206. package/src/components/layout/market-summary.ts +9 -6
  207. package/src/components/layout/pane/capture-status.ts +1 -1
  208. package/src/components/layout/pane/footer/index.tsx +1 -0
  209. package/src/components/layout/pane/footer/model.ts +38 -5
  210. package/src/components/layout/shell/chrome.ts +19 -6
  211. package/src/components/layout/shell/index.tsx +2 -1
  212. package/src/components/layout/shell/pane/layers.tsx +19 -1
  213. package/src/components/layout/status-bar.tsx +2 -2
  214. package/src/components/market-board/index.tsx +11 -3
  215. package/src/components/onboarding/onboarding-frame.tsx +1 -1
  216. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  217. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  218. package/src/components/onboarding/portfolio-step/positions-panel.tsx +2 -2
  219. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  220. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  221. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  222. package/src/components/pane-settings-dialog/value.ts +8 -1
  223. package/src/components/pane-settings-dialog.tsx +44 -13
  224. package/src/components/sign-in-code-panel.tsx +27 -19
  225. package/src/components/ui/column-grid.tsx +48 -4
  226. package/src/components/ui/country-flag-art.tsx +180 -0
  227. package/src/components/ui/country-flag.tsx +118 -12
  228. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  229. package/src/components/ui/data-table/opentui/model.ts +109 -2
  230. package/src/components/ui/data-table/types.ts +1 -1
  231. package/src/components/ui/display.tsx +10 -2
  232. package/src/components/ui/index.ts +3 -1
  233. package/src/components/ui/logo-mark.tsx +11 -2
  234. package/src/components/ui/query-bar.tsx +1 -1
  235. package/src/components/ui/row-notes.ts +79 -0
  236. package/src/core/state/app/layout.ts +6 -4
  237. package/src/core/state/app/state.ts +9 -0
  238. package/src/core/state/app/types.ts +3 -0
  239. package/src/data/cached-query.ts +8 -1
  240. package/src/data/config/chart-settings.ts +3 -3
  241. package/src/data/config/home.ts +10 -2
  242. package/src/data/config/layout.ts +4 -1
  243. package/src/data/config/store/node.ts +4 -0
  244. package/src/data/config/store/normalize.ts +13 -3
  245. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  246. package/src/data/json-storage.ts +2 -0
  247. package/src/data/saved-copies.ts +123 -0
  248. package/src/docs/snapshot.json +422 -112
  249. package/src/i18n/es.ts +30 -13
  250. package/src/i18n/ja.ts +30 -13
  251. package/src/i18n/ko.ts +30 -13
  252. package/src/i18n/zh-cn.ts +30 -13
  253. package/src/i18n/zh-tw.ts +30 -13
  254. package/src/layout/desks.ts +1 -1
  255. package/src/layout/launch-layout.ts +1 -1
  256. package/src/layout/pane-manager/floating-actions.ts +5 -3
  257. package/src/layout/pane-manager/floating.ts +43 -1
  258. package/src/layout/pane-manager/index.ts +2 -0
  259. package/src/layout/selected-ticker.ts +74 -0
  260. package/src/market-data/coordinator/financials.ts +10 -2
  261. package/src/market-data/coordinator/index.ts +3 -1
  262. package/src/market-data/coordinator/quotes.ts +4 -2
  263. package/src/market-data/depositary-pair.ts +251 -0
  264. package/src/market-data/futures-board.ts +1 -1
  265. package/src/market-data/futures-contract.ts +124 -40
  266. package/src/market-data/fx-closes.ts +17 -2
  267. package/src/market-data/hooks.tsx +19 -11
  268. package/src/market-data/market/change-basis.ts +81 -11
  269. package/src/market-data/market/dated-previous-close.ts +203 -0
  270. package/src/market-data/market/freshness.ts +34 -5
  271. package/src/market-data/market/futures-week.ts +68 -0
  272. package/src/market-data/market/period-return.ts +163 -0
  273. package/src/market-data/market/status.ts +16 -4
  274. package/src/market-data/market/trading-sessions.ts +13 -0
  275. package/src/market-data/market/year-to-date.ts +8 -13
  276. package/src/market-data/options-alternatives.ts +60 -0
  277. package/src/market-data/performance.ts +20 -14
  278. package/src/market-data/perpetual-premium.ts +32 -0
  279. package/src/market-data/published-apac-sessions.ts +2 -1
  280. package/src/market-data/published-futures-sessions.ts +69 -0
  281. package/src/market-data/quotes/contributions.ts +25 -3
  282. package/src/market-data/quotes/freshness.ts +42 -0
  283. package/src/market-data/quotes/intraday-bar.ts +37 -0
  284. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  285. package/src/market-data/quotes/resolution.ts +7 -2
  286. package/src/market-data/selectors.ts +3 -0
  287. package/src/market-data/tax-equivalent.ts +1 -1
  288. package/src/market-data/ticker-price-returns.ts +3 -1
  289. package/src/news/aggregator.ts +5 -1
  290. package/src/news/news-model.ts +4 -0
  291. package/src/news/types.ts +11 -0
  292. package/src/notifications/app-notifier.ts +1 -1
  293. package/src/notifications/notification-log.ts +6 -4
  294. package/src/plugins/auto-update.ts +2 -2
  295. package/src/plugins/builtin/account-management/index.tsx +1 -0
  296. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  297. package/src/plugins/builtin/alerts/alert-engine.ts +34 -20
  298. package/src/plugins/builtin/alerts/calendar-events.ts +429 -0
  299. package/src/plugins/builtin/alerts/cli.ts +533 -85
  300. package/src/plugins/builtin/alerts/command.ts +12 -10
  301. package/src/plugins/builtin/alerts/constants.ts +1 -1
  302. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  303. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  304. package/src/plugins/builtin/alerts/events.ts +107 -5
  305. package/src/plugins/builtin/alerts/fired-log.ts +119 -0
  306. package/src/plugins/builtin/alerts/format.ts +10 -3
  307. package/src/plugins/builtin/alerts/headless.ts +107 -41
  308. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  309. package/src/plugins/builtin/alerts/history-rows.ts +92 -0
  310. package/src/plugins/builtin/alerts/history.ts +2 -0
  311. package/src/plugins/builtin/alerts/index.tsx +107 -30
  312. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  313. package/src/plugins/builtin/alerts/levels.ts +3 -3
  314. package/src/plugins/builtin/alerts/live.ts +3 -3
  315. package/src/plugins/builtin/alerts/metric-command.ts +61 -0
  316. package/src/plugins/builtin/alerts/metric-data.ts +70 -0
  317. package/src/plugins/builtin/alerts/metric-model.ts +175 -0
  318. package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
  319. package/src/plugins/builtin/alerts/pane.tsx +130 -49
  320. package/src/plugins/builtin/alerts/price.ts +35 -0
  321. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  322. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  323. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  324. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  325. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  326. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  327. package/src/plugins/builtin/alerts/storage.ts +38 -12
  328. package/src/plugins/builtin/alerts/targets.ts +12 -3
  329. package/src/plugins/builtin/alerts/types.ts +3 -0
  330. package/src/plugins/builtin/analytics/index.tsx +8 -2
  331. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  332. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  333. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  334. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  335. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  336. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  337. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  338. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  339. package/src/plugins/builtin/attention/pane.tsx +6 -2
  340. package/src/plugins/builtin/awards/headless.ts +7 -3
  341. package/src/plugins/builtin/awards/model.ts +18 -0
  342. package/src/plugins/builtin/awards/pane.tsx +6 -3
  343. package/src/plugins/builtin/backtest/headless.ts +13 -8
  344. package/src/plugins/builtin/backtest/pane.tsx +9 -4
  345. package/src/plugins/builtin/backtest/presets.ts +29 -3
  346. package/src/plugins/builtin/backtest/rules.ts +41 -5
  347. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  348. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  349. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  350. package/src/plugins/builtin/broker-manager/index.tsx +24 -14
  351. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  352. package/src/plugins/builtin/broker-manager/model.ts +18 -3
  353. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  354. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  355. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  356. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  357. package/src/plugins/builtin/broker-trading/controller.ts +66 -24
  358. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  359. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  360. package/src/plugins/builtin/broker-trading/index.tsx +19 -1
  361. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  362. package/src/plugins/builtin/broker-trading/order-feed.ts +83 -10
  363. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  364. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  365. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  366. package/src/plugins/builtin/broker-trading/pane.tsx +111 -24
  367. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  368. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  369. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  370. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  371. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  372. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  373. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  374. package/src/plugins/builtin/builtin-plugin-meta.ts +2 -2
  375. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  376. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  377. package/src/plugins/builtin/catalysts/model.ts +51 -5
  378. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  379. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  380. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  381. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  382. package/src/plugins/builtin/changelog/index.tsx +1 -0
  383. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +4 -1
  384. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +3 -2
  385. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  386. package/src/plugins/builtin/chart-composer/cli-options.ts +7 -10
  387. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -3
  388. package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -0
  389. package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
  390. package/src/plugins/builtin/chart-composer/editor.tsx +9 -4
  391. package/src/plugins/builtin/chart-composer/formula.ts +71 -18
  392. package/src/plugins/builtin/chart-composer/headless-schema.ts +42 -29
  393. package/src/plugins/builtin/chart-composer/headless.ts +266 -37
  394. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  395. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  396. package/src/plugins/builtin/chart-composer/pane.tsx +144 -30
  397. package/src/plugins/builtin/chart-composer/presets.ts +50 -15
  398. package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
  399. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  400. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  401. package/src/plugins/builtin/chart-composer/session-history.ts +31 -28
  402. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  403. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  404. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +44 -31
  405. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  406. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  407. package/src/plugins/builtin/chat/content/command-suggestions.ts +92 -0
  408. package/src/plugins/builtin/chat/content/composer.tsx +13 -6
  409. package/src/plugins/builtin/chat/content/footer.tsx +6 -3
  410. package/src/plugins/builtin/chat/content/index.tsx +51 -22
  411. package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
  412. package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
  413. package/src/plugins/builtin/chat/index.tsx +23 -0
  414. package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
  415. package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
  416. package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
  417. package/src/plugins/builtin/chat/pane-links/commands.ts +265 -0
  418. package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
  419. package/src/plugins/builtin/chat/pane-links/open.ts +9 -2
  420. package/src/plugins/builtin/chat/people.ts +1 -1
  421. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
  422. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  423. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  424. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  425. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  426. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  427. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  428. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  429. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  430. package/src/plugins/builtin/cloud/plugin.tsx +1 -1
  431. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  432. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  433. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  434. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  435. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  436. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  437. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  438. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  439. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  440. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  441. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  442. package/src/plugins/builtin/company-attention/client.ts +117 -1
  443. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  444. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  445. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  446. package/src/plugins/builtin/company-attention/model.ts +33 -7
  447. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  448. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  449. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  450. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  451. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  452. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  453. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  454. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  455. package/src/plugins/builtin/composite-plugins.ts +2 -1
  456. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  457. package/src/plugins/builtin/connections/index.ts +1 -0
  458. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  459. package/src/plugins/builtin/correlation/headless.ts +5 -3
  460. package/src/plugins/builtin/cot/headless.ts +28 -6
  461. package/src/plugins/builtin/cot/model.ts +12 -0
  462. package/src/plugins/builtin/cot/pane.tsx +3 -2
  463. package/src/plugins/builtin/cpi/headless.ts +5 -1
  464. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  465. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  466. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  467. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  468. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  469. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  470. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  471. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  472. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  473. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  474. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  475. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  476. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  477. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  478. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  479. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  480. package/src/plugins/builtin/debug/index.tsx +1 -0
  481. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  482. package/src/plugins/builtin/docs/index.tsx +1 -1
  483. package/src/plugins/builtin/docs/pane.tsx +2 -2
  484. package/src/plugins/builtin/docs/targets.ts +1 -1
  485. package/src/plugins/builtin/doe/client.ts +5 -1
  486. package/src/plugins/builtin/doe/headless.ts +12 -6
  487. package/src/plugins/builtin/doe/model.ts +43 -6
  488. package/src/plugins/builtin/doe/pane.tsx +18 -11
  489. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  490. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  491. package/src/plugins/builtin/earnings/board.tsx +253 -50
  492. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  493. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  494. package/src/plugins/builtin/earnings/client.ts +4 -3
  495. package/src/plugins/builtin/earnings/headless.ts +53 -15
  496. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  497. package/src/plugins/builtin/earnings/index.tsx +15 -22
  498. package/src/plugins/builtin/earnings/model.ts +17 -12
  499. package/src/plugins/builtin/earnings/scope.ts +89 -0
  500. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  501. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  502. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  503. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  504. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  505. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  506. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  507. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  508. package/src/plugins/builtin/econ/calendar-model.ts +144 -27
  509. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  510. package/src/plugins/builtin/econ/figures.ts +72 -0
  511. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  512. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  513. package/src/plugins/builtin/econ/index.tsx +144 -27
  514. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  515. package/src/plugins/builtin/econ/types.ts +34 -1
  516. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  517. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  518. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  519. package/src/plugins/builtin/econ-statistics/headless.ts +87 -28
  520. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  521. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  522. package/src/plugins/builtin/econ-statistics/stats.ts +104 -0
  523. package/src/plugins/builtin/econ-statistics/view.ts +19 -1
  524. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  525. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  526. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  527. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  528. package/src/plugins/builtin/equity-screener/pane.tsx +47 -12
  529. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  530. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  531. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  532. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  533. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  534. package/src/plugins/builtin/exposure/charts.tsx +2 -2
  535. package/src/plugins/builtin/exposure/headless.ts +51 -6
  536. package/src/plugins/builtin/exposure/index.tsx +28 -2
  537. package/src/plugins/builtin/exposure/model.ts +20 -1
  538. package/src/plugins/builtin/exposure/pane.tsx +10 -5
  539. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  540. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  541. package/src/plugins/builtin/futures/index.tsx +1 -0
  542. package/src/plugins/builtin/futures/model.ts +12 -10
  543. package/src/plugins/builtin/futures/returns.ts +8 -36
  544. package/src/plugins/builtin/futures/table.tsx +3 -3
  545. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  546. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  547. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  548. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  549. package/src/plugins/builtin/fx-matrix/client.ts +20 -8
  550. package/src/plugins/builtin/fx-matrix/headless.ts +37 -16
  551. package/src/plugins/builtin/fx-matrix/index.tsx +25 -13
  552. package/src/plugins/builtin/fx-matrix/live-legs.ts +34 -0
  553. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  554. package/src/plugins/builtin/gpu/headless.ts +9 -4
  555. package/src/plugins/builtin/help/index.tsx +13 -3
  556. package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
  557. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  558. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  559. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  560. package/src/plugins/builtin/holders/client.ts +13 -1
  561. package/src/plugins/builtin/holders/format.ts +28 -17
  562. package/src/plugins/builtin/holders/headless.ts +46 -7
  563. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  564. package/src/plugins/builtin/holders/pane.tsx +79 -15
  565. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  566. package/src/plugins/builtin/holders/table-model.ts +2 -1
  567. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  568. package/src/plugins/builtin/insider/headless.ts +1 -1
  569. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  570. package/src/plugins/builtin/insider/signals.tsx +1 -1
  571. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  572. package/src/plugins/builtin/iv-history/client.ts +20 -0
  573. package/src/plugins/builtin/iv-history/headless.ts +7 -4
  574. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  575. package/src/plugins/builtin/iv-history/model.ts +13 -4
  576. package/src/plugins/builtin/iv-history/series.ts +3 -1
  577. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  578. package/src/plugins/builtin/jobs/model.ts +4 -15
  579. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  580. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  581. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  582. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  583. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  584. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  585. package/src/plugins/builtin/macro-day/model.ts +29 -8
  586. package/src/plugins/builtin/macro-day/pane.tsx +51 -13
  587. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  588. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  589. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  590. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  591. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  592. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  593. package/src/plugins/builtin/market-movers/client.ts +33 -19
  594. package/src/plugins/builtin/market-movers/footer.ts +2 -2
  595. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  596. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  597. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  598. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  599. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  600. package/src/plugins/builtin/market-movers/table.ts +4 -1
  601. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  602. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  603. package/src/plugins/builtin/members/breadth-pane.tsx +81 -0
  604. package/src/plugins/builtin/members/client.ts +19 -4
  605. package/src/plugins/builtin/members/headless.ts +24 -10
  606. package/src/plugins/builtin/members/index.tsx +9 -9
  607. package/src/plugins/builtin/members/model.ts +23 -4
  608. package/src/plugins/builtin/members/pane.tsx +31 -14
  609. package/src/plugins/builtin/mna/client.ts +1 -0
  610. package/src/plugins/builtin/mna/detail.tsx +20 -32
  611. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  612. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  613. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  614. package/src/plugins/builtin/mna/headless.ts +6 -13
  615. package/src/plugins/builtin/mna/model.ts +93 -15
  616. package/src/plugins/builtin/mna/pane.tsx +5 -4
  617. package/src/plugins/builtin/news/headless.ts +12 -6
  618. package/src/plugins/builtin/news/index.tsx +10 -1
  619. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  620. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  621. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  622. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  623. package/src/plugins/builtin/notes/cli.ts +49 -14
  624. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  625. package/src/plugins/builtin/options/analytics.ts +26 -2
  626. package/src/plugins/builtin/options/carry.ts +2 -2
  627. package/src/plugins/builtin/options/index.tsx +1 -1
  628. package/src/plugins/builtin/options/model-spot.ts +5 -2
  629. package/src/plugins/builtin/options/strike-window.ts +2 -1
  630. package/src/plugins/builtin/options/table.ts +1 -7
  631. package/src/plugins/builtin/options/view.tsx +30 -13
  632. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  633. package/src/plugins/builtin/options-positioning/client.ts +19 -0
  634. package/src/plugins/builtin/options-positioning/headless.ts +54 -14
  635. package/src/plugins/builtin/options-positioning/index.tsx +3 -3
  636. package/src/plugins/builtin/options-positioning/model.ts +47 -8
  637. package/src/plugins/builtin/options-positioning/pane.tsx +68 -38
  638. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  639. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  640. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  641. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  642. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  643. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  644. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  645. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  646. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  647. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  648. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  649. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  650. package/src/plugins/builtin/perps/freshness.ts +14 -9
  651. package/src/plugins/builtin/perps/headless.ts +3 -1
  652. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  653. package/src/plugins/builtin/perps/live-rows.ts +168 -0
  654. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  655. package/src/plugins/builtin/perps/pane.tsx +49 -26
  656. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  657. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  658. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  659. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  660. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  661. package/src/plugins/builtin/portfolio-list/cli/render.ts +54 -22
  662. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  663. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  664. package/src/plugins/builtin/portfolio-list/headless.ts +7 -4
  665. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  666. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  667. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  668. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  669. package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
  670. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  671. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  672. package/src/plugins/builtin/power/client.ts +4 -1
  673. package/src/plugins/builtin/power/evidence.ts +22 -7
  674. package/src/plugins/builtin/power/gas.tsx +5 -1
  675. package/src/plugins/builtin/power/pane.tsx +8 -1
  676. package/src/plugins/builtin/power/prices.tsx +10 -3
  677. package/src/plugins/builtin/rate-path/pane.tsx +2 -2
  678. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  679. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  680. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  681. package/src/plugins/builtin/research/event-model.ts +3 -1
  682. package/src/plugins/builtin/research/event-sources.ts +12 -4
  683. package/src/plugins/builtin/research/index.tsx +2 -1
  684. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  685. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  686. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  687. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  688. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  689. package/src/plugins/builtin/research/relative-valuation-pane.tsx +80 -13
  690. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  691. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  692. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  693. package/src/plugins/builtin/scanner/feed.ts +2 -2
  694. package/src/plugins/builtin/scanner/index.ts +24 -1
  695. package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
  696. package/src/plugins/builtin/scanner/live-feed.ts +168 -0
  697. package/src/plugins/builtin/scanner/live-headless.ts +114 -0
  698. package/src/plugins/builtin/scanner/live-model.ts +351 -0
  699. package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
  700. package/src/plugins/builtin/scanner/live-track.ts +186 -0
  701. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  702. package/src/plugins/builtin/sec/forms.ts +13 -0
  703. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  704. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  705. package/src/plugins/builtin/sec/headless.ts +85 -8
  706. package/src/plugins/builtin/sec/index.tsx +58 -12
  707. package/src/plugins/builtin/sectors/client.ts +2 -1
  708. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  709. package/src/plugins/builtin/series-inventory.ts +3 -0
  710. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  711. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  712. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  713. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  714. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  715. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  716. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  717. package/src/plugins/builtin/shared/macro-releases.ts +65 -0
  718. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  719. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  720. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  721. package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
  722. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  723. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  724. package/src/plugins/builtin/shared/use-quote-board.ts +8 -2
  725. package/src/plugins/builtin/shared/volatility/pricing.ts +7 -1
  726. package/src/plugins/builtin/short-interest/client.ts +2 -0
  727. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  728. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  729. package/src/plugins/builtin/short-interest/model.ts +70 -19
  730. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  731. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  732. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  733. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  734. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  735. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  736. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  737. package/src/plugins/builtin/short-interest/types.ts +9 -0
  738. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  739. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  740. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  741. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  742. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  743. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  744. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  745. package/src/plugins/builtin/themes/headless.ts +11 -6
  746. package/src/plugins/builtin/themes/model.ts +15 -5
  747. package/src/plugins/builtin/themes/pane.tsx +27 -8
  748. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  749. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  750. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  751. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  752. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  753. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  754. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  755. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  756. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  757. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  758. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  759. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  760. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  761. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  762. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  763. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  764. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  765. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  766. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  767. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  768. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  769. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  770. package/src/plugins/builtin/ticker-detail/quote-footer.ts +14 -4
  771. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  772. package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
  773. package/src/plugins/builtin/vol-surface/client.ts +7 -4
  774. package/src/plugins/builtin/vol-surface/headless.ts +71 -13
  775. package/src/plugins/builtin/vol-surface/index.tsx +2 -2
  776. package/src/plugins/builtin/vol-surface/model.ts +26 -9
  777. package/src/plugins/builtin/vol-surface/pane.tsx +44 -7
  778. package/src/plugins/builtin/vol-surface/tables.ts +31 -3
  779. package/src/plugins/builtin/volatility/dvol.ts +46 -0
  780. package/src/plugins/builtin/volatility/model.ts +5 -10
  781. package/src/plugins/builtin/volatility/pane.tsx +2 -2
  782. package/src/plugins/builtin/volatility/series.ts +26 -0
  783. package/src/plugins/builtin/world-indices/footer.ts +1 -1
  784. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  785. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  786. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  787. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  788. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  789. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  790. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  791. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  792. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  793. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  794. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  795. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  796. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  797. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  798. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  799. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  800. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  801. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  802. package/src/plugins/bundle.ts +1 -1
  803. package/src/plugins/catalog-browser.ts +15 -9
  804. package/src/plugins/compat.ts +3 -3
  805. package/src/plugins/dependencies.ts +75 -14
  806. package/src/plugins/extracted-plugins.ts +132 -34
  807. package/src/plugins/host-link.ts +149 -34
  808. package/src/plugins/installer.ts +35 -10
  809. package/src/plugins/loader.ts +206 -38
  810. package/src/plugins/manager-node.ts +2 -2
  811. package/src/plugins/marketplace/deactivation.ts +22 -0
  812. package/src/plugins/marketplace/model.ts +2 -2
  813. package/src/plugins/marketplace/packs.ts +1 -1
  814. package/src/plugins/ownership.ts +1 -1
  815. package/src/plugins/peer-retry.ts +155 -0
  816. package/src/plugins/registry/contributions.ts +3 -1
  817. package/src/plugins/registry/index.ts +4 -3
  818. package/src/plugins/registry/plugin-state.ts +3 -0
  819. package/src/plugins/seed-notice.ts +20 -0
  820. package/src/plugins/shortcut-argument.ts +39 -0
  821. package/src/portfolio/allocation.ts +1 -1
  822. package/src/portfolio/collection-name.ts +31 -0
  823. package/src/portfolio/column-values.ts +15 -13
  824. package/src/portfolio/cost-fx.ts +296 -19
  825. package/src/portfolio/manual-lots.ts +75 -0
  826. package/src/portfolio/mutations.ts +60 -22
  827. package/src/portfolio/suffixed-listings.ts +209 -0
  828. package/src/portfolio/totals-currency.ts +24 -0
  829. package/src/public/__snapshots__/public-api.test.ts.snap +15 -0
  830. package/src/public/time-series.ts +11 -8
  831. package/src/remote/schema.ts +1 -1
  832. package/src/renderers/browser/app-services.ts +1 -7
  833. package/src/renderers/browser/config-host.ts +5 -55
  834. package/src/renderers/browser/main.tsx +30 -60
  835. package/src/renderers/dom/boot-frame-page.ts +187 -0
  836. package/src/renderers/dom/boot-frame.ts +237 -0
  837. package/src/renderers/dom/build-assets.ts +46 -8
  838. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  839. package/src/renderers/dom/host/ascii-text.ts +16 -2
  840. package/src/renderers/dom/host/box.tsx +43 -2
  841. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  842. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  843. package/src/renderers/dom/host/image-surface.tsx +49 -0
  844. package/src/renderers/dom/host/media-surface.tsx +24 -18
  845. package/src/renderers/dom/host/mouse.ts +30 -0
  846. package/src/renderers/dom/host/size-observer.ts +1 -1
  847. package/src/renderers/dom/host/style.ts +1 -1
  848. package/src/renderers/dom/styles.css +76 -0
  849. package/src/renderers/dom/test-utils.tsx +2 -1
  850. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  851. package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
  852. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  853. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  854. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  855. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  856. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  857. package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
  858. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
  859. package/src/renderers/electrobun/bun/desktop/update.ts +70 -3
  860. package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
  861. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  862. package/src/renderers/electrobun/bun/index.ts +36 -2
  863. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  864. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  865. package/src/renderers/electrobun/shared/app-name.ts +17 -0
  866. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  867. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  868. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  869. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  870. package/src/renderers/electrobun/view/config-host.ts +3 -0
  871. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
  872. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  873. package/src/renderers/electrobun/view/main.tsx +30 -4
  874. package/src/renderers/electrobun/view/news-source.ts +5 -5
  875. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  876. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  877. package/src/renderers/opentui/browser-open.ts +88 -0
  878. package/src/renderers/opentui/host.tsx +5 -14
  879. package/src/renderers/opentui/image/loader.ts +3 -2
  880. package/src/renderers/opentui/native-smoke.ts +10 -1
  881. package/src/renderers/opentui/pane-image/index.ts +2 -1
  882. package/src/renderers/opentui/render-lib.ts +253 -0
  883. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  884. package/src/renderers/opentui/start.tsx +1 -1
  885. package/src/renderers/opentui/toast-host.tsx +71 -43
  886. package/src/renderers/share/layout-view.tsx +2 -2
  887. package/src/renderers/share/main.tsx +4 -4
  888. package/src/renderers/share/view.tsx +1 -1
  889. package/src/series/resolve.ts +22 -6
  890. package/src/series/standalone.ts +30 -2
  891. package/src/series/types.ts +8 -1
  892. package/src/shares/api.ts +4 -1
  893. package/src/shares/pane.ts +1 -1
  894. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  895. package/src/sources/gloomberb-cloud/index.ts +32 -16
  896. package/src/sources/gloomberb-cloud/news.ts +39 -0
  897. package/src/sources/gloomberb-cloud/normalizers.ts +16 -1
  898. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  899. package/src/sources/listing-symbols.ts +37 -0
  900. package/src/sources/provider-errors.ts +16 -2
  901. package/src/sources/provider-router/batches.ts +10 -2
  902. package/src/sources/provider-router/financial-routes.ts +21 -3
  903. package/src/sources/provider-router/financials.ts +15 -2
  904. package/src/sources/provider-router/history.ts +58 -15
  905. package/src/sources/provider-router/index.ts +146 -10
  906. package/src/sources/provider-router/primary.ts +1 -1
  907. package/src/sources/provider-router/search.ts +13 -2
  908. package/src/state/app/bootstrap.ts +23 -0
  909. package/src/state/app/context/index.tsx +3 -0
  910. package/src/state/hooks/inline-tickers.ts +30 -5
  911. package/src/sync/auth-transition.ts +19 -9
  912. package/src/sync/baseline.ts +10 -4
  913. package/src/sync/controller.ts +67 -17
  914. package/src/sync/core-contributors.ts +46 -14
  915. package/src/sync/react.ts +4 -1
  916. package/src/sync/types.ts +3 -0
  917. package/src/team/collections-sync.ts +2 -1
  918. package/src/team/collections.ts +178 -17
  919. package/src/telemetry/crash-reports.ts +17 -4
  920. package/src/telemetry/usage-counts.ts +0 -18
  921. package/src/test-support/builtin-panes.ts +1 -1
  922. package/src/theme/colors.ts +11 -30
  923. package/src/theme/ui-tokens.ts +37 -1
  924. package/src/tickers/company-name-listing.ts +210 -33
  925. package/src/tickers/company-name.ts +59 -0
  926. package/src/tickers/index-roots.ts +47 -0
  927. package/src/tickers/instrument-label.ts +5 -1
  928. package/src/tickers/listing-venues.ts +23 -0
  929. package/src/tickers/metadata.ts +10 -0
  930. package/src/tickers/perpetual-listing.ts +5 -2
  931. package/src/tickers/search/bare-symbol.ts +36 -0
  932. package/src/tickers/search/home-listing.ts +75 -0
  933. package/src/tickers/search/index.ts +111 -33
  934. package/src/tickers/search/ranking.ts +64 -5
  935. package/src/tickers/search/types.ts +5 -0
  936. package/src/tickers/search/upsert.ts +29 -0
  937. package/src/tickers/terminal-codes.ts +416 -40
  938. package/src/time-series/bar-aggregation.ts +243 -0
  939. package/src/time-series/base-series.ts +315 -0
  940. package/src/time-series/chart-bounds.ts +349 -0
  941. package/src/time-series/chart-seed.ts +142 -0
  942. package/src/time-series/daily-valuation.ts +62 -0
  943. package/src/time-series/economic.ts +5 -0
  944. package/src/time-series/field-catalog.ts +1 -3
  945. package/src/time-series/forward-valuation.ts +32 -0
  946. package/src/time-series/fundamentals.ts +173 -10
  947. package/src/time-series/history-acquisition.ts +499 -0
  948. package/src/time-series/hooks.ts +1 -0
  949. package/src/time-series/leverage.ts +100 -0
  950. package/src/time-series/market-resolution.ts +4 -2
  951. package/src/time-series/market.ts +2 -1
  952. package/src/time-series/price-comparison.ts +175 -30
  953. package/src/time-series/price-units.ts +72 -2
  954. package/src/time-series/range.ts +9 -1
  955. package/src/time-series/resolution.ts +174 -16
  956. package/src/time-series/resolve-context.ts +161 -0
  957. package/src/time-series/resolve.ts +185 -1587
  958. package/src/time-series/series-name.ts +38 -0
  959. package/src/time-series/series-presentation.ts +242 -0
  960. package/src/time-series/spec.ts +13 -7
  961. package/src/time-series/studies.ts +377 -82
  962. package/src/time-series/tail-reconcile.ts +121 -0
  963. package/src/time-series/transforms.ts +1 -0
  964. package/src/time-series/types.ts +34 -2
  965. package/src/time-series/use-chart-resolution.ts +4 -5
  966. package/src/time-series/valuation-releases.ts +39 -0
  967. package/src/types/broker.ts +10 -0
  968. package/src/types/config.ts +14 -0
  969. package/src/types/data-provider.ts +23 -1
  970. package/src/types/desktop-window.ts +2 -0
  971. package/src/types/exchange-rate.ts +6 -0
  972. package/src/types/financials.ts +145 -8
  973. package/src/types/headless.ts +117 -9
  974. package/src/types/instrument.ts +6 -0
  975. package/src/types/plugin.ts +66 -9
  976. package/src/types/price-history.ts +2 -0
  977. package/src/types/ticker.ts +13 -0
  978. package/src/types/trading.ts +59 -1
  979. package/src/ui/ascii-font.ts +13 -1
  980. package/src/ui/host.tsx +6 -1
  981. package/src/updater/command-names.ts +180 -0
  982. package/src/updater/index.ts +10 -5
  983. package/src/utils/calendar-date.ts +32 -15
  984. package/src/utils/cash-runway.ts +241 -0
  985. package/src/utils/central-banks.ts +42 -0
  986. package/src/utils/cli-output.ts +259 -80
  987. package/src/utils/contract-month.ts +16 -0
  988. package/src/utils/crypto-pair.ts +61 -3
  989. package/src/utils/currency-units.ts +29 -0
  990. package/src/utils/datetime-format.ts +10 -0
  991. package/src/utils/debug-log.ts +1 -1
  992. package/src/utils/decimal-comma.ts +39 -6
  993. package/src/utils/exchange-announcements.ts +71 -0
  994. package/src/utils/exchange-rate-snapshot.ts +10 -0
  995. package/src/utils/financial-statements.ts +89 -5
  996. package/src/utils/format.ts +34 -16
  997. package/src/utils/fundamentals.ts +150 -34
  998. package/src/utils/fx-market-hours.ts +10 -1
  999. package/src/utils/latest-financial-period.ts +8 -0
  1000. package/src/utils/linux-libc.ts +54 -0
  1001. package/src/utils/market-capitalization.ts +111 -15
  1002. package/src/utils/max-drawdown.ts +64 -0
  1003. package/src/utils/network-failure.ts +86 -0
  1004. package/src/utils/option-expiry.ts +186 -7
  1005. package/src/utils/options.ts +10 -0
  1006. package/src/utils/plugin-proxy-hosts.json +1 -0
  1007. package/src/utils/price-earnings.ts +11 -5
  1008. package/src/utils/price-history.ts +23 -8
  1009. package/src/utils/price-window.ts +131 -0
  1010. package/src/utils/release-date.ts +47 -0
  1011. package/src/utils/sec.ts +3 -0
  1012. package/src/utils/throttled-fetch.ts +11 -4
  1013. package/src/utils/trailing-eps.ts +67 -0
  1014. package/src/utils/typed-text.ts +21 -0
  1015. package/src/utils/utc-time.ts +24 -1
  1016. package/src/version.ts +6 -0
  1017. package/src/cli/pane-functions/screenshot.ts +0 -2122
  1018. package/src/renderers/browser/first-screen.ts +0 -193
@@ -20,11 +20,23 @@ import {
20
20
  concentration,
21
21
  pairedReturns,
22
22
  regressReturns,
23
+ RISK_TAIL_CONFIDENCE,
24
+ RISK_TAIL_MINIMUM,
23
25
  rollingBasketRisk,
24
26
  rollingBeta,
25
27
  sinceBasketRisk,
26
28
  subtractReturns,
27
29
  } from "./risk-math";
30
+ import {
31
+ repriceBook,
32
+ RISK_SHOCK_LIMITS,
33
+ riskCashLines,
34
+ type RiskAssetShift,
35
+ type RiskBookLine,
36
+ type RiskCashLine,
37
+ type RiskFxShift,
38
+ type RiskRepricing,
39
+ } from "./risk-book";
28
40
  import {
29
41
  calculateAccountPerformance,
30
42
  calculateBrinson,
@@ -69,32 +81,51 @@ interface PortfolioRiskHolding {
69
81
  /** Why the holding is outside the basket; null when it qualifies. */
70
82
  leftOut: string | null;
71
83
  }
72
- /** A holding outside the basket, with its share of market value when one is known. */
84
+ /** A holding or a currency's cash outside the basket, with its share of the book when one is known. */
73
85
  interface RiskLeftOut {
74
86
  id: string;
75
87
  symbol: string;
76
88
  reason: string;
77
89
  value: number | null;
78
90
  share: number | null;
91
+ /** Set on a currency's cash, which is never in the basket and does not make a report incomplete. */
92
+ cash?: true;
93
+ }
94
+ /** One currency of the book's cash, valued in the account currency. */
95
+ interface RiskCashHolding extends RiskCashLine {
96
+ id: string;
97
+ /** "TRY cash". */
98
+ symbol: string;
99
+ /** Signed, in the portfolio currency at the current rate; null without a rate. */
100
+ value: number | null;
79
101
  }
80
102
  /** What the basket views cover of the account. */
81
103
  export interface RiskCoverage {
82
104
  currency: string;
83
- /** Gross current value of every holding that has one, in the portfolio currency. */
105
+ /**
106
+ * Gross current value of the book in the portfolio currency: every holding
107
+ * that has one, and the cash.
108
+ */
84
109
  marketValue: number;
85
110
  coveredValue: number;
86
- /** Covered share of market value; an upper bound while `unvalued` holdings have no value. */
111
+ /** Covered share of the book, cash included; an upper bound while `unvalued` lines have no value. */
87
112
  share: number | null;
113
+ /** Gross value of the holdings alone, and the covered share of it, which `sufficient` reads. */
114
+ holdingsValue?: number;
115
+ holdingsShare?: number | null;
116
+ /** Gross value of the cash in the portfolio currency. */
117
+ cashValue?: number;
88
118
  holdings: number;
89
119
  /** Holdings that qualify for the basket. */
90
120
  covered: number;
91
121
  /** Covered holdings whose returns were converted to USD from their listing currency. */
92
122
  converted: number;
123
+ /** Holdings and cash lines nothing values. */
93
124
  unvalued: number;
94
125
  minimumShare: number;
95
- /** The basket views estimate only when qualifying holdings reach the minimum share. */
126
+ /** The basket views estimate only when qualifying holdings reach the minimum share of the holdings, cash aside. */
96
127
  sufficient: boolean;
97
- /** Largest first. */
128
+ /** Holdings and cash, largest first. */
98
129
  leftOut: RiskLeftOut[];
99
130
  }
100
131
  export interface RiskDisplayRow {
@@ -112,10 +143,16 @@ export interface RiskDisplayRow {
112
143
  interaction?: number;
113
144
  /** Holdings rows only: why the holding is outside the covered basket. */
114
145
  leftOut?: string;
115
- /** VaR and expected shortfall only: the loss `value` is on the covered basket's current value (`amountBase`), in `amountCurrency`. */
146
+ /**
147
+ * A loss or change in money beside `value`, in `amountCurrency`: VaR and
148
+ * expected shortfall on the covered basket's current value (`amountBase`),
149
+ * a shock on the repriced line.
150
+ */
116
151
  amount?: number;
117
152
  amountCurrency?: string;
118
153
  amountBase?: number;
154
+ /** What a tail loss in money is taken on: the basket's value and share of the book, and what it leaves out. */
155
+ basis?: string;
119
156
  }
120
157
  /** The tail-loss rows, which also read in money on the covered basket. */
121
158
  const TAIL_ROW_IDS: ReadonlySet<string> = new Set(["var", "es"]);
@@ -144,6 +181,9 @@ export interface RiskShifts {
144
181
  equity: number;
145
182
  rates: number;
146
183
  volatility: number;
184
+ /** Currencies' moves against USD and holdings' own price moves, applied together to every line of the book. */
185
+ fx?: RiskFxShift[];
186
+ assets?: RiskAssetShift[];
147
187
  }
148
188
  /** The benchmark the basket's returns, active return and tracking error are measured against. */
149
189
  const RISK_BENCHMARK = "SPY";
@@ -330,6 +370,22 @@ function outsideValue(
330
370
  const value = resolvePortfolioMarketValue(metrics, unit != null && Number.isFinite(unit) ? unit : null)?.gross;
331
371
  return value != null && Number.isFinite(value) ? value : null;
332
372
  }
373
+ /** Cash in the portfolio currency at the load's rates (USD per unit); null without a rate. */
374
+ function cashValue(line: RiskCashLine, accountCurrency: string, rates: Readonly<Record<string, number>>): number | null {
375
+ const unit = resolveCurrencyUnit(line.currency);
376
+ if (unit.currency === accountCurrency) return line.amount / unit.divisor;
377
+ const usd = unit.currency === "USD" ? 1 : rates[unit.currency];
378
+ const account = accountCurrency === "USD" ? 1 : rates[accountCurrency];
379
+ const value = usd != null && usd > 0 && account != null && account > 0 ? (line.amount / unit.divisor) * usd / account : Number.NaN;
380
+ return Number.isFinite(value) ? value : null;
381
+ }
382
+ /** Why a currency's cash is outside the basket, and for one in another currency, what moves its value. */
383
+ function cashReason(line: RiskCashLine, accountCurrency: string): string {
384
+ const own = resolveCurrencyUnit(line.currency).currency;
385
+ return own === accountCurrency
386
+ ? "Cash is outside the equity basket"
387
+ : `Cash is outside the equity basket; its ${accountCurrency} value moves with ${own}`;
388
+ }
333
389
  /** USD returns in the account currency, or none with the reason its daily closes cannot convert them. */
334
390
  function accountReturns(returns: readonly DatedReturn[], account: AccountFx): { returns: DatedReturn[]; error: string | null } {
335
391
  if (account.error) return { returns: [], error: account.error };
@@ -355,67 +411,84 @@ const shareText = (share: number) =>
355
411
  share < 0.001 ? "under 0.1%" : `${(share * 100).toFixed(1)}%`;
356
412
  const convertedText = (coverage: RiskCoverage) =>
357
413
  coverage.converted ? `${holdingCount(coverage.converted)} converted from local currency` : null;
414
+ /** Whole percents of shares that add up to one, the remainders handed out largest first, so a line of them adds up to 100. */
415
+ function wholePercents(shares: readonly number[]): number[] {
416
+ const raw = shares.map((share) => share * 100);
417
+ const whole = raw.map((value) => Math.floor(value + 1e-9));
418
+ let left = Math.round(raw.reduce((sum, value) => sum + value, 0)) - whole.reduce((sum, value) => sum + value, 0);
419
+ const order = raw.map((_, index) => index).sort((a, b) => raw[b]! - whole[b]! - (raw[a]! - whole[a]!));
420
+ for (const index of order) {
421
+ if (left <= 0) break;
422
+ whole[index]! += 1;
423
+ left -= 1;
424
+ }
425
+ return whole;
426
+ }
427
+ const percentText = (percent: number, share: number) => (percent > 0 ? `${percent}%` : share > 0 ? "under 1%" : "0%");
428
+ /** Lines the coverage line names before "N more". */
429
+ const NAMED_EXCLUSIONS = 2;
358
430
  /**
359
- * "covers 78% of market value · 9 holdings left out · 2 converted from local
360
- * currency", or null when every holding is in the basket in its own USD listing.
361
- * The compact result for Ask Gloom reads this form; the report and the pane
362
- * name what is left out with `riskCoverageHeadline`.
431
+ * "basket 48,286 USD = 72% of book; left out: BTC-USD 10%, TRY cash 18%": the
432
+ * value the basket views estimate on, its share of the whole book (every
433
+ * holding and the cash), and what it leaves out, largest first, the percents
434
+ * adding up to 100. Past three lines left out the rest read "7 more 14%". The
435
+ * basket's share reads "at most" while a line has no value, and a line nothing
436
+ * values is named with "value unknown". Converted listings are counted after.
363
437
  */
364
- export function riskCoverageText(coverage: RiskCoverage | undefined): string | null {
438
+ export function riskCoverageLine(coverage: RiskCoverage | undefined): string | null {
365
439
  if (!coverage) return null;
366
- const converted = convertedText(coverage);
367
- if (!coverage.leftOut.length) return converted;
368
- const covers = coverage.share == null
369
- ? "covers an unknown share of market value"
370
- : `covers ${coverage.unvalued ? "at most " : ""}${coveragePercent(coverage.share)}% of market value`;
371
- return [covers, `${holdingCount(coverage.leftOut.length)} left out`, ...(converted ? [converted] : [])].join(" · ");
440
+ const named = coverage.leftOut.length <= NAMED_EXCLUSIONS + 1 ? coverage.leftOut : coverage.leftOut.slice(0, NAMED_EXCLUSIONS);
441
+ const rest = coverage.leftOut.slice(named.length);
442
+ const restShare = rest.reduce((sum, row) => sum + (row.share ?? 0), 0);
443
+ const shares = [coverage.share ?? 0, ...named.map((row) => row.share ?? 0), ...(rest.length ? [restShare] : [])];
444
+ const percents = wholePercents(shares);
445
+ const basket = `basket ${formatNumber(coverage.coveredValue, 0)} ${coverage.currency}${coverage.share == null ? "" : ` = ${coverage.unvalued ? "at most " : ""}${percentText(percents[0]!, shares[0]!)} of book`}`;
446
+ const items = [
447
+ ...named.map((row, index) => `${row.symbol} ${row.share == null ? "value unknown" : percentText(percents[index + 1]!, row.share)}`),
448
+ ...(rest.length ? [`${rest.length} more${restShare > 0 ? ` ${percentText(percents.at(-1)!, restShare)}` : ""}`] : []),
449
+ ];
450
+ return [`${basket}${items.length ? `; left out: ${items.join(", ")}` : ""}`, convertedText(coverage)].filter(Boolean).join(" · ");
372
451
  }
373
- /** Holdings named before "+N more" in the exclusion text. */
374
- const NAMED_EXCLUSIONS = 2;
452
+ /** Whether the basket leaves out a holding, which makes a report incomplete; cash never is in it. */
453
+ export const riskHoldingsLeftOut = (coverage: RiskCoverage) => coverage.leftOut.some((row) => !row.cash);
375
454
  /**
376
- * What the basket leaves out, by name and combined share, from the same
377
- * covered share every other line reads: "excludes SQM, 12% of value" or
378
- * "excludes SQM, ALB +1 more, 41% of value". The share is the complement of the
379
- * covered percent, so the two always add to 100; it reads "at least" while a
380
- * holding has no value, and a holding nothing values is named with "value
381
- * unknown". Null when every holding is in the basket.
455
+ * "historical, 1-day, 95%, 60 daily returns": how VaR and expected shortfall
456
+ * are estimated, from the sample they read; without an estimate, how many
457
+ * returns it needs.
382
458
  */
383
- export function riskExclusionText(coverage: RiskCoverage | undefined): string | null {
384
- if (!coverage?.leftOut.length) return null;
385
- const named = coverage.leftOut.slice(0, NAMED_EXCLUSIONS).map((row) => row.symbol).join(", ");
386
- const more = coverage.leftOut.length - NAMED_EXCLUSIONS;
387
- const names = more > 0 ? `${named} +${more} more` : named;
388
- if (coverage.share == null || !coverage.leftOut.some((row) => (row.share ?? 0) > 0))
389
- return `excludes ${names}, value unknown`;
390
- const percent = 100 - coveragePercent(coverage.share);
391
- return `excludes ${names}, ${coverage.unvalued ? "at least " : ""}${percent > 0 ? `${percent}%` : "under 1%"} of value`;
392
- }
393
- /** The line that leads what the basket views cover: what is left out, then what converted from local currency. */
394
- export function riskCoverageHeadline(coverage: RiskCoverage | undefined): string | null {
395
- if (!coverage) return null;
396
- return [riskExclusionText(coverage), convertedText(coverage)].filter(Boolean).join(" · ") || null;
459
+ function riskTailMethod(samples: number, estimated: boolean): string {
460
+ const head = `historical, 1-day, ${Math.round(RISK_TAIL_CONFIDENCE * 100)}%`;
461
+ return estimated
462
+ ? `${head}, ${samples} daily returns`
463
+ : `${head}; needs ${RISK_TAIL_MINIMUM} daily returns${samples ? `, has ${samples}` : ""}`;
397
464
  }
465
+ /** The unit of the concentration shares, which divide the priced holdings' value, cash aside. */
466
+ export const HOLDINGS_SHARE_UNIT = "% holdings";
398
467
  /** A reason reads as the tail of a sentence, so its first word loses its capital unless it is an acronym ("FX", "USD"). */
399
468
  const lowerFirst = (text: string) => (/^[A-Z][a-z]/.test(text) ? text[0]!.toLowerCase() + text.slice(1) : text);
400
- /** One sentence per left-out holding, largest first, naming the holding and why it is out. */
469
+ /** One sentence per holding or cash left out, largest first, naming it and why it is out. */
401
470
  export function riskCoverageNotices(coverage: RiskCoverage | undefined): string[] {
402
471
  if (!coverage?.leftOut.length) return [];
403
472
  return coverage.leftOut.map(
404
473
  (row) =>
405
- `${row.symbol} (${row.share == null ? "value unknown" : `${shareText(row.share)} of market value`}) is excluded from the risk estimate: ${lowerFirst(row.reason.replace(/\.$/, ""))}.`,
474
+ `${row.symbol} (${row.share == null ? "value unknown" : `${shareText(row.share)} of the book`}) is excluded from the risk estimate: ${lowerFirst(row.reason.replace(/\.$/, ""))}.`,
406
475
  );
407
476
  }
408
- /** Why the basket views show no estimate, when too little of the account qualifies. */
477
+ /** Why the basket views show no estimate, when too little of the holdings qualifies. */
409
478
  export function riskCoverageShortfall(
410
479
  coverage: RiskCoverage | undefined,
411
480
  ): { title: string; message: string } | null {
412
481
  if (!coverage || coverage.sufficient) return null;
413
482
  if (!coverage.holdings) return { title: "No holdings in this portfolio.", message: "" };
414
483
  const minimum = Math.round(coverage.minimumShare * 100);
484
+ // A share of what is invested: cash is no holding the basket could take.
485
+ const share = coverage.holdingsShare !== undefined ? coverage.holdingsShare : coverage.share;
486
+ const base = coverage.holdingsValue ?? coverage.marketValue;
415
487
  const reasons = new Map<string, { share: number; count: number }>();
416
488
  for (const row of coverage.leftOut) {
489
+ if (row.cash) continue;
417
490
  const entry = reasons.get(row.reason) ?? { share: 0, count: 0 };
418
- entry.share += row.share ?? 0;
491
+ entry.share += row.value != null && base > 0 ? row.value / base : 0;
419
492
  entry.count += 1;
420
493
  reasons.set(row.reason, entry);
421
494
  }
@@ -423,14 +496,51 @@ export function riskCoverageShortfall(
423
496
  ([, left], [, right]) => right.share - left.share || right.count - left.count,
424
497
  )[0] ?? [];
425
498
  return {
426
- title: coverage.covered === 0 || coverage.share == null
427
- ? `No holding qualifies for basket estimates, which need ${minimum}% of market value.`
428
- : `Qualifying holdings cover ${coverage.unvalued ? "at most " : ""}${coveragePercent(coverage.share)}% of market value; basket estimates need ${minimum}%.`,
499
+ title: coverage.covered === 0 || share == null
500
+ ? `No holding qualifies for basket estimates, which need ${minimum}% of the holdings' value.`
501
+ : `Qualifying holdings cover ${coverage.unvalued ? "at most " : ""}${coveragePercent(share)}% of the holdings' value; basket estimates need ${minimum}%.`,
429
502
  message: reason
430
- ? `Most of what is left out: ${reason}${largest!.share > 0 ? ` (${shareText(largest!.share)} of market value)` : ""}.`
503
+ ? `Most of what is left out: ${reason}${largest!.share > 0 ? ` (${shareText(largest!.share)} of the holdings' value)` : ""}.`
431
504
  : "",
432
505
  };
433
506
  }
507
+ /**
508
+ * The stress rows of the given shocks: each line they move, its change in
509
+ * percent of its own value and in money, then the book's total, in percent of
510
+ * its net value with the cash.
511
+ */
512
+ /** The Stress row that totals the currency and price shocks over the whole book. */
513
+ export const BOOK_TOTAL_ROW_ID = "shock:book";
514
+ /** A Stress row of the currency and price shocks, which reprice the book without the basket. */
515
+ export function isShockRow(row: Pick<RiskDisplayRow, "id">): boolean {
516
+ return row.id.startsWith("shock:");
517
+ }
518
+ function repricingRows(repricing: RiskRepricing, currency: string, asOf: string): RiskDisplayRow[] {
519
+ const money = (value: number) => `${formatNumber(value, 0)} ${currency}`;
520
+ return [
521
+ ...repricing.lines.map((line) => ({
522
+ id: `shock:${line.id}`,
523
+ label: line.label,
524
+ value: line.percent,
525
+ unit: "%",
526
+ percentile: null,
527
+ asOf,
528
+ detail: `${line.shocks.join(", ")}; ${line.before == null || line.after == null ? "value unknown, not repriced" : `${money(line.before)} to ${money(line.after)}`}`,
529
+ ...(line.change != null ? { amount: line.change, amountCurrency: currency } : {}),
530
+ })),
531
+ {
532
+ id: BOOK_TOTAL_ROW_ID,
533
+ label: "Book total",
534
+ value: repricing.percent,
535
+ unit: "%",
536
+ percentile: null,
537
+ asOf,
538
+ detail: `${repricing.scenario}; of ${money(repricing.bookValue)} book, cash included${repricing.unvalued.length ? `; ${repricing.unvalued.join(", ")} without a value not repriced` : ""}`,
539
+ amount: repricing.change,
540
+ amountCurrency: currency,
541
+ },
542
+ ];
543
+ }
434
544
  /**
435
545
  * Basket estimates use the holdings that qualify, reweighted among themselves.
436
546
  * Every other holding stays listed with its reason and counts in the market
@@ -443,6 +553,8 @@ export function buildPortfolioRisk(
443
553
  evidence: PortfolioRiskEvidence | null = null,
444
554
  shifts: RiskShifts = DEFAULT_RISK_SHIFTS,
445
555
  window: RiskWindowRequest = {},
556
+ /** The book's cash by currency; the portfolio's own entry when left out. */
557
+ cash: readonly RiskCashLine[] = riskCashLines(portfolio, null),
446
558
  ) {
447
559
  if (
448
560
  ![shifts.equity, shifts.rates, shifts.volatility].every(Number.isFinite) ||
@@ -450,7 +562,9 @@ export function buildPortfolioRisk(
450
562
  Math.abs(shifts.equity) > 100 ||
451
563
  Math.abs(shifts.rates) > 500 ||
452
564
  shifts.volatility < -50 ||
453
- shifts.volatility > 100
565
+ shifts.volatility > 100 ||
566
+ [...(shifts.fx ?? []), ...(shifts.assets ?? [])].some((shift) =>
567
+ !Number.isFinite(shift.percent) || shift.percent < RISK_SHOCK_LIMITS.minimum || shift.percent > RISK_SHOCK_LIMITS.maximum)
454
568
  )
455
569
  throw new Error("Stress shifts exceed the supported range");
456
570
  if (
@@ -580,33 +694,59 @@ export function buildPortfolioRisk(
580
694
  leftOut,
581
695
  };
582
696
  });
697
+ // Each currency's cash once, valued in the portfolio currency.
698
+ const cashTotals = new Map<string, number>();
699
+ for (const line of cash)
700
+ if (Number.isFinite(line.amount) && line.amount !== 0)
701
+ cashTotals.set(line.currency, (cashTotals.get(line.currency) ?? 0) + line.amount);
702
+ const cashHoldings: RiskCashHolding[] = [...cashTotals].map(([currency, amount]) => ({
703
+ id: `cash:${currency}`,
704
+ symbol: `${currency} cash`,
705
+ currency,
706
+ amount,
707
+ value: cashValue({ currency, amount }, portfolio.currency, rates),
708
+ }));
583
709
  const qualifying = holdings.filter((row) => row.leftOut == null);
584
710
  const valued = holdings.filter((row) => row.marketValue != null);
585
- const marketValue = valued.reduce((sum, row) => sum + row.marketValue!, 0);
711
+ const holdingsValue = valued.reduce((sum, row) => sum + row.marketValue!, 0);
712
+ // Cash counts in the book the coverage is a share of, at its gross value as a short does.
713
+ const cashGross = cashHoldings.reduce((sum, row) => sum + Math.abs(row.value ?? 0), 0);
714
+ const marketValue = holdingsValue + cashGross;
586
715
  const coveredValue = qualifying.reduce((sum, row) => sum + row.value!, 0);
587
716
  const share = marketValue > 0 ? coveredValue / marketValue : null;
588
- const sufficient = qualifying.length > 0 && share != null && share >= RISK_MIN_COVERAGE;
717
+ // Whether the basket is most of what is invested: cash is no holding the basket could have taken.
718
+ const holdingsShare = holdingsValue > 0 ? coveredValue / holdingsValue : null;
719
+ const sufficient = qualifying.length > 0 && holdingsShare != null && holdingsShare >= RISK_MIN_COVERAGE;
720
+ const bookShare = (value: number | null) => value != null && marketValue > 0 ? value / marketValue : null;
589
721
  const coverage: RiskCoverage = {
590
722
  currency: portfolio.currency,
591
723
  marketValue,
592
724
  coveredValue,
593
725
  share,
726
+ holdingsValue,
727
+ holdingsShare,
728
+ cashValue: cashGross,
594
729
  holdings: holdings.length,
595
730
  covered: qualifying.length,
596
731
  converted: qualifying.filter((row) => row.convertedFrom != null).length,
597
- unvalued: holdings.length - valued.length,
732
+ unvalued: holdings.length - valued.length + cashHoldings.filter((row) => row.value == null).length,
598
733
  minimumShare: RISK_MIN_COVERAGE,
599
734
  sufficient,
600
- leftOut: holdings
601
- .filter((row) => row.leftOut != null)
602
- .sort((a, b) => (b.marketValue ?? -1) - (a.marketValue ?? -1))
603
- .map((row) => ({
604
- id: row.id,
605
- symbol: row.symbol,
606
- reason: row.leftOut!,
607
- value: row.marketValue,
608
- share: row.marketValue != null && marketValue > 0 ? row.marketValue / marketValue : null,
609
- })),
735
+ leftOut: [
736
+ ...holdings
737
+ .filter((row) => row.leftOut != null)
738
+ .map((row): RiskLeftOut => ({
739
+ id: row.id,
740
+ symbol: row.symbol,
741
+ reason: row.leftOut!,
742
+ value: row.marketValue,
743
+ share: bookShare(row.marketValue),
744
+ })),
745
+ ...cashHoldings.map((row): RiskLeftOut => {
746
+ const value = row.value == null ? null : Math.abs(row.value);
747
+ return { id: row.id, symbol: row.symbol, reason: cashReason(row, portfolio.currency), value, share: bookShare(value), cash: true };
748
+ }),
749
+ ].sort((a, b) => (b.value ?? -1) - (a.value ?? -1)),
610
750
  };
611
751
  // Weights renormalize over the covered basket; nothing outside it is approximated into it.
612
752
  const members = sufficient ? qualifying : [];
@@ -774,6 +914,26 @@ export function buildPortfolioRisk(
774
914
  value: regression ? regression.beta * stress.shock * 100 : null,
775
915
  };
776
916
  });
917
+ // The given currency and price shocks reprice every line of the book, cash included, at once.
918
+ const bookLines: RiskBookLine[] = [
919
+ ...holdings.map((row) => ({
920
+ id: row.id,
921
+ label: row.symbol,
922
+ currency: row.convertedFrom ?? row.currency,
923
+ // A holding outside the USD marks keeps its gross value, signed as its position is.
924
+ value: row.value ?? (row.marketValue == null ? null : row.quantity < 0 ? -row.marketValue : row.marketValue),
925
+ listing: { symbol: row.symbol, exchange: row.exchange },
926
+ })),
927
+ ...cashHoldings.map((row) => ({ id: row.id, label: row.symbol, currency: row.currency, value: row.value, listing: null })),
928
+ ];
929
+ const repricing = repriceBook(bookLines, portfolio.currency, shifts.fx, shifts.assets);
930
+ if (repricing?.unmatched.length) {
931
+ const held = holdings.map((row) => row.symbol);
932
+ for (const { kind, name } of repricing.unmatched)
933
+ notes.push(kind === "currency"
934
+ ? `Nothing in "${portfolio.name}" moves with ${name} against USD, so the ${name} shift changes nothing.`
935
+ : `"${portfolio.name}" holds no ${name}, so its shift changes nothing${held.length ? `; it holds ${held.slice(0, 8).join(", ")}${held.length > 8 ? ` and ${held.length - 8} more` : ""}` : ""}.`);
936
+ }
777
937
  if (sufficient)
778
938
  for (const factor of factors)
779
939
  if (factor.samples === 0)
@@ -806,10 +966,15 @@ export function buildPortfolioRisk(
806
966
  return {
807
967
  ...row,
808
968
  percentile: row.rank.percentile,
809
- // The method (price returns, bought and held or at fixed current weights) is in docs; the footer keeps room for coverage.
810
- detail: filed && row.value == null && TAIL_ROW_IDS.has(row.id) ? `${row.samples} sessions; needs 60` : `${row.samples} sessions`,
969
+ // The tail rows name how they are estimated; the other rows' method (price returns, bought and held or at fixed current weights) is in docs.
970
+ detail: TAIL_ROW_IDS.has(row.id) ? riskTailMethod(row.samples, row.value != null) : `${row.samples} sessions`,
811
971
  ...(tail
812
- ? { amount: (row.value! / 100) * coverage.coveredValue, amountCurrency: coverage.currency, amountBase: coverage.coveredValue }
972
+ ? {
973
+ amount: (row.value! / 100) * coverage.coveredValue,
974
+ amountCurrency: coverage.currency,
975
+ amountBase: coverage.coveredValue,
976
+ basis: riskCoverageLine(coverage) ?? undefined,
977
+ }
813
978
  : {}),
814
979
  };
815
980
  }),
@@ -818,21 +983,48 @@ export function buildPortfolioRisk(
818
983
  percentile: row.rank.percentile,
819
984
  detail: `${row.samples} sessions; R² ${row.regression?.rSquared?.toFixed(2) ?? "--"}; independent ETF proxy`,
820
985
  })),
821
- // Largest current value first, left-out holdings in place; unvalued ones last.
822
- holdings: [...holdings]
823
- .sort((a, b) => (b.marketValue ?? -1) - (a.marketValue ?? -1))
824
- .map((row) => ({
825
- id: row.id,
826
- label: row.symbol,
827
- value: row.weight == null ? null : row.weight * 100,
828
- unit: "% basket",
829
- percentile: null,
830
- asOf: row.priceAsOf,
831
- detail: row.leftOut
832
- ? row.leftOut
833
- : `${row.quantity} shares; ${formatNumber(row.value ?? undefined)} ${portfolio.currency}${row.markSource === "close" || row.markSource === "regular-close" ? ` at ${row.priceAsOf} close` : ""}${row.convertedFrom ? ` from ${row.convertedFrom} at daily FX` : ""}; history ${row.historyAsOf}`,
834
- ...(row.leftOut ? { leftOut: row.leftOut } : {}),
835
- })),
986
+ // Largest current value first, left-out holdings and each currency's cash in place; unvalued ones last.
987
+ holdings: [
988
+ ...holdings.map((row) => ({
989
+ size: row.marketValue,
990
+ row: {
991
+ id: row.id,
992
+ label: row.symbol,
993
+ value: row.weight == null ? null : row.weight * 100,
994
+ unit: "% basket",
995
+ percentile: null,
996
+ asOf: row.priceAsOf,
997
+ detail: row.leftOut
998
+ ? row.leftOut
999
+ : `${row.quantity} shares; ${formatNumber(row.value ?? undefined)} ${portfolio.currency}${row.markSource === "close" || row.markSource === "regular-close" ? ` at ${row.priceAsOf} close` : ""}${row.convertedFrom ? ` from ${row.convertedFrom} at daily FX` : ""}; history ${row.historyAsOf}`,
1000
+ ...(row.leftOut ? { leftOut: row.leftOut } : {}),
1001
+ } as RiskDisplayRow,
1002
+ })),
1003
+ ...cashHoldings.map((row) => {
1004
+ const amount = `${formatNumber(row.amount)} ${row.currency}`;
1005
+ const foreign = resolveCurrencyUnit(row.currency).currency !== portfolio.currency;
1006
+ return {
1007
+ size: row.value == null ? null : Math.abs(row.value),
1008
+ row: {
1009
+ id: row.id,
1010
+ label: row.symbol,
1011
+ value: null,
1012
+ unit: "% basket",
1013
+ percentile: null,
1014
+ asOf: market.fetchedAt,
1015
+ // What it is worth in the account currency and what moves it; the value column says it is left out.
1016
+ detail: [
1017
+ !foreign ? amount : row.value == null ? `${amount}; no current ${row.currency} rate values it` : `${amount} = ${formatNumber(row.value)} ${portfolio.currency}`,
1018
+ ...(foreign ? [`moves with ${row.currency}`] : []),
1019
+ "outside the basket",
1020
+ ].join("; "),
1021
+ leftOut: cashReason(row, portfolio.currency),
1022
+ } as RiskDisplayRow,
1023
+ };
1024
+ }),
1025
+ ]
1026
+ .sort((a, b) => (b.size ?? -1) - (a.size ?? -1))
1027
+ .map(({ row }) => row),
836
1028
  correlation: correlation.map((row) => ({
837
1029
  id: `${row.left}/${row.right}`,
838
1030
  label: row.label,
@@ -842,15 +1034,19 @@ export function buildPortfolioRisk(
842
1034
  asOf: row.asOf ?? null,
843
1035
  detail: `${row.samples ?? 0} matched daily returns`,
844
1036
  })),
845
- stress: stresses.map((row) => ({
846
- id: row.id,
847
- label: row.label,
848
- value: row.value,
849
- unit: "%",
850
- percentile: null,
851
- asOf: row.regression?.asOf ?? null,
852
- detail: `${row.regression?.samples ?? 0} sessions; R² ${row.regression?.rSquared?.toFixed(2) ?? "--"}; ${row.source}`,
853
- })),
1037
+ stress: [
1038
+ // A regression scenario moves the basket by its beta; it is a share of the basket, not of the book.
1039
+ ...stresses.map((row) => ({
1040
+ id: row.id,
1041
+ label: row.label,
1042
+ value: row.value,
1043
+ unit: "%",
1044
+ percentile: null,
1045
+ asOf: row.regression?.asOf ?? null,
1046
+ detail: `% of basket; ${row.regression?.samples ?? 0} sessions; R² ${row.regression?.rSquared?.toFixed(2) ?? "--"}; ${row.source}`,
1047
+ })),
1048
+ ...(repricing ? repricingRows(repricing, portfolio.currency, market.fetchedAt) : []),
1049
+ ],
854
1050
  performance: performance
855
1051
  ? [
856
1052
  {
@@ -951,25 +1147,27 @@ export function buildPortfolioRisk(
951
1147
  )
952
1148
  : [],
953
1149
  };
1150
+ // Concentration is of the priced holdings, cash aside, and says so with the value it divides.
1151
+ const holdingsBase = book ? `Share of ${formatNumber(book.gross, 0)} ${portfolio.currency} in priced holdings, cash aside` : "";
954
1152
  if (book)
955
1153
  rows.holdings.unshift(
956
1154
  {
957
1155
  id: "top",
958
1156
  label: "Largest holding",
959
1157
  value: book.top * 100,
960
- unit: "% value",
1158
+ unit: HOLDINGS_SHARE_UNIT,
961
1159
  percentile: null,
962
1160
  asOf: market.fetchedAt,
963
- detail: "Current value of every priced holding",
1161
+ detail: holdingsBase,
964
1162
  },
965
1163
  {
966
1164
  id: "top-five",
967
1165
  label: "Largest five",
968
1166
  value: book.topFive * 100,
969
- unit: "% value",
1167
+ unit: HOLDINGS_SHARE_UNIT,
970
1168
  percentile: null,
971
1169
  asOf: market.fetchedAt,
972
- detail: "Current value of every priced holding",
1170
+ detail: holdingsBase,
973
1171
  },
974
1172
  {
975
1173
  id: "hhi",
@@ -978,7 +1176,7 @@ export function buildPortfolioRisk(
978
1176
  unit: "ratio",
979
1177
  percentile: null,
980
1178
  asOf: market.fetchedAt,
981
- detail: `${book.effectiveHoldings.toFixed(2)} effective holdings`,
1179
+ detail: `${book.effectiveHoldings.toFixed(2)} effective holdings, cash aside`,
982
1180
  },
983
1181
  );
984
1182
  return {
@@ -997,9 +1195,11 @@ export function buildPortfolioRisk(
997
1195
  evidence,
998
1196
  rows,
999
1197
  coverage,
1198
+ cash: cashHoldings,
1199
+ repricing,
1000
1200
  complete:
1001
1201
  sufficient &&
1002
- coverage.leftOut.length === 0 &&
1202
+ !riskHoldingsLeftOut(coverage) &&
1003
1203
  metrics.some((row) => row.value != null),
1004
1204
  warnings: [...new Set(warnings)],
1005
1205
  notes,
@@ -1029,18 +1229,11 @@ export const riskValue = (row: RiskDisplayRow) =>
1029
1229
  : row.value == null
1030
1230
  ? "--"
1031
1231
  : `${row.value.toFixed(2)}${row.unit === "%" ? "%" : ` ${row.unit}`}${riskAmount(row)}`;
1032
- /** "220,476 USD basket": the value a tail loss in money is taken on, or null for a row without one. */
1033
- export function riskAmountBase(row: Pick<RiskDisplayRow, "amountBase" | "amountCurrency">): string | null {
1034
- return row.amountBase != null && Number.isFinite(row.amountBase) && row.amountCurrency
1035
- ? `${formatNumber(row.amountBase, 0)} ${row.amountCurrency} basket`
1036
- : null;
1037
- }
1038
- /** A row's evidence with the basket a tail loss in money is taken on. */
1232
+ /** A row's evidence with what a tail loss in money is taken on: the basket, its share of the book and what it leaves out. */
1039
1233
  export function riskEvidence(row: RiskDisplayRow): string {
1040
- const base = riskAmountBase(row);
1041
- return base ? `${row.detail}; of ${base}` : row.detail;
1234
+ return row.basis ? `${row.detail}; ${row.basis}` : row.detail;
1042
1235
  }
1043
- /** " ($5,735)": a tail loss in money beside its percent. */
1236
+ /** " ($5,735)": a loss or change in money beside its percent. */
1044
1237
  function riskAmount(row: RiskDisplayRow): string {
1045
1238
  if (row.amount == null || !Number.isFinite(row.amount) || !row.amountCurrency) return "";
1046
1239
  return ` (${formatCurrency(row.amount, row.amountCurrency, 0)})`;
@@ -6,6 +6,7 @@ import {
6
6
  loadScenarioMarket,
7
7
  type ScenarioLoaderDependencies,
8
8
  } from "../options-scenario/client";
9
+ import { optionModelSpot } from "../options/model-spot";
9
10
  import { createGloomberbCloudProvider } from "../../../sources/gloomberb-cloud";
10
11
  import { canonicalExchange } from "../../../utils/exchanges";
11
12
 
@@ -142,14 +143,28 @@ export async function loadPortfolioOptionBook(
142
143
  option.impliedVolatility <= 0
143
144
  )
144
145
  throw new Error("Contract implied volatility unavailable");
146
+ // Valued where the chain's IV was measured, as OMON values the chain: a
147
+ // closed session's quotes at the time they were taken and the session's
148
+ // close. Over the hours left now, a same-day IV would price the contract
149
+ // under its quote before the open.
150
+ const valuation = optionModelSpot(
151
+ market.underlyingQuote,
152
+ market.chain,
153
+ dependencies.now?.() ?? Date.now(),
154
+ exchange,
155
+ );
156
+ if (!valuation)
157
+ throw new Error(
158
+ "Fresh matching Cloud spot, chain, rate and dividend inputs are required",
159
+ );
145
160
  const position: ScenarioPosition = {
146
161
  symbol: market.symbol,
147
162
  exchange,
148
163
  currency: market.currency,
149
- spot: market.spot,
164
+ spot: valuation.price,
150
165
  rate: market.rate,
151
166
  dividendYield: market.dividendYield,
152
- asOf: market.asOf,
167
+ asOf: valuation.valuationTime,
153
168
  legs: [
154
169
  {
155
170
  id: String(contract.conId),