gloomberb 0.16.4 → 0.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (554) hide show
  1. package/README.md +14 -91
  2. package/package.json +4 -1
  3. package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
  4. package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
  5. package/src/account/billing.ts +57 -0
  6. package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
  7. package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
  8. package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
  9. package/src/account/session.ts +16 -0
  10. package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
  11. package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
  12. package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
  13. package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
  14. package/src/api-client/data.ts +24 -2
  15. package/src/api-client/earnings.ts +6 -0
  16. package/src/api-client/futures-curve.ts +56 -0
  17. package/src/api-client/index.ts +4 -1
  18. package/src/api-client/market-discovery.ts +10 -1
  19. package/src/api-client/paths.ts +7 -0
  20. package/src/api-client/research-activity.ts +15 -10
  21. package/src/api-client/types.ts +17 -1
  22. package/src/api-client/yield-curves.ts +8 -0
  23. package/src/app/global-shortcuts.ts +15 -1
  24. package/src/app/pane-runtime/ticker-open-runtime.ts +7 -3
  25. package/src/architecture/core-builtin-allowlist.json +4 -13
  26. package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
  27. package/src/capabilities/chart-series.ts +11 -1
  28. package/src/cli/commands/crypto-hints.ts +7 -0
  29. package/src/cli/commands/fred-series.ts +61 -0
  30. package/src/cli/commands/market.ts +407 -104
  31. package/src/cli/commands/news-hints.ts +62 -0
  32. package/src/cli/commands/news-search.ts +53 -0
  33. package/src/cli/commands/options-leaps.ts +5 -2
  34. package/src/cli/commands/overview.ts +93 -20
  35. package/src/cli/commands/remote.ts +2 -1
  36. package/src/cli/commands/search.ts +82 -9
  37. package/src/cli/commands/system.ts +55 -8
  38. package/src/cli/commands/ticker.ts +88 -11
  39. package/src/cli/context.ts +45 -14
  40. package/src/cli/desktop-pane-shot.ts +59 -7
  41. package/src/cli/earnings-calendar.ts +71 -0
  42. package/src/cli/freshness.ts +18 -7
  43. package/src/cli/glossary.ts +429 -0
  44. package/src/cli/history-rows.ts +48 -7
  45. package/src/cli/index-roots.ts +7 -0
  46. package/src/cli/index.ts +21 -7
  47. package/src/cli/known-gaps.ts +27 -0
  48. package/src/cli/listing-arg.ts +417 -56
  49. package/src/cli/not-a-ticker.ts +12 -5
  50. package/src/cli/pane-functions/access-gate.ts +5 -0
  51. package/src/cli/pane-functions/capabilities.ts +3 -2
  52. package/src/cli/pane-functions/catalog.ts +35 -5
  53. package/src/cli/pane-functions/data.ts +12 -8
  54. package/src/cli/pane-functions/discovery.ts +1 -0
  55. package/src/cli/pane-functions/dom.ts +20 -6
  56. package/src/cli/pane-functions/freshness.ts +363 -43
  57. package/src/cli/pane-functions/function-help.ts +12 -5
  58. package/src/cli/pane-functions/headless.ts +45 -17
  59. package/src/cli/pane-functions/index.ts +63 -10
  60. package/src/cli/pane-functions/market-session.ts +22 -8
  61. package/src/cli/pane-functions/options.ts +63 -22
  62. package/src/cli/pane-functions/report-notices.ts +25 -7
  63. package/src/cli/pane-functions/report.ts +15 -8
  64. package/src/cli/pane-functions/resolver.ts +49 -12
  65. package/src/cli/pane-functions/screenshot.ts +110 -23
  66. package/src/cli/report-tables.ts +3 -0
  67. package/src/cli/result.ts +4 -1
  68. package/src/cli/staged-tickers.ts +52 -0
  69. package/src/cli/symbol-args.ts +9 -0
  70. package/src/cli/symbol-list.ts +172 -0
  71. package/src/cli/ticker-resolution.ts +223 -30
  72. package/src/cli/types.ts +5 -0
  73. package/src/components/chart/composite/axis-overlays.tsx +6 -2
  74. package/src/components/chart/composite/composite-chart.tsx +40 -6
  75. package/src/components/chart/composite/legend.tsx +49 -2
  76. package/src/components/chart/composite/panel-surface.tsx +44 -17
  77. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  78. package/src/components/command-bar/panel/index.tsx +11 -3
  79. package/src/components/command-bar/panel/runtime.ts +3 -0
  80. package/src/components/command-bar/panel/types.ts +2 -0
  81. package/src/components/command-bar/routes/root/provider-search.ts +4 -3
  82. package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
  83. package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
  84. package/src/components/command-bar/workflow/tickers.ts +23 -4
  85. package/src/components/layout/detached-pane-shell.tsx +9 -0
  86. package/src/components/layout/floating-pane.tsx +3 -0
  87. package/src/components/layout/header.tsx +20 -5
  88. package/src/components/layout/pane/content.tsx +7 -13
  89. package/src/components/layout/pane/footer/index.tsx +6 -2
  90. package/src/components/layout/pane/footer/model.ts +35 -1
  91. package/src/components/layout/pane/header.tsx +24 -1
  92. package/src/components/layout/pane/index.tsx +12 -2
  93. package/src/components/layout/pane/sidebar.tsx +78 -10
  94. package/src/components/layout/shell/active-drag.ts +21 -5
  95. package/src/components/layout/shell/drag/index.ts +39 -9
  96. package/src/components/layout/shell/drag/live.ts +61 -51
  97. package/src/components/layout/shell/drag/runtime.ts +54 -12
  98. package/src/components/layout/shell/index.tsx +25 -7
  99. package/src/components/layout/shell/menu.ts +5 -0
  100. package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
  101. package/src/components/layout/shell/pane/layers.tsx +192 -45
  102. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
  103. package/src/components/markdown-text.tsx +62 -20
  104. package/src/components/metric-treemap/heat-surface.tsx +10 -1
  105. package/src/components/onboarding/account-step/form-panel.tsx +1 -1
  106. package/src/components/onboarding/account-step/index.tsx +1 -1
  107. package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
  108. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  109. package/src/components/onboarding/onboarding-keyboard.ts +1 -1
  110. package/src/components/onboarding/onboarding-wizard.tsx +2 -2
  111. package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
  112. package/src/components/onboarding/wizard-account.ts +2 -2
  113. package/src/components/pane-template-wizard.tsx +9 -1
  114. package/src/components/price-selector-dialog.tsx +11 -2
  115. package/src/components/sign-in-gate.tsx +3 -3
  116. package/src/components/ticker/list-table-view.tsx +24 -1
  117. package/src/components/ui/action-row.tsx +2 -1
  118. package/src/components/ui/button.tsx +7 -1
  119. package/src/components/ui/choice-dialog.tsx +6 -4
  120. package/src/components/ui/confirm-dialog.tsx +28 -18
  121. package/src/components/ui/data-table/index.tsx +17 -6
  122. package/src/components/ui/data-table/opentui/index.tsx +37 -6
  123. package/src/components/ui/data-table/types.ts +12 -0
  124. package/src/components/ui/dialog-actions.tsx +64 -0
  125. package/src/components/ui/display.tsx +17 -3
  126. package/src/components/ui/frame.tsx +35 -2
  127. package/src/components/ui/icon.tsx +2 -0
  128. package/src/components/ui/text-prompt-dialog.tsx +11 -9
  129. package/src/data/cached-query.ts +2 -0
  130. package/src/data/config/store/normalize.ts +7 -2
  131. package/src/data/ticker-repository.ts +5 -0
  132. package/src/data/ticker-store.ts +15 -0
  133. package/src/docs/content.ts +215 -0
  134. package/src/docs/load.ts +139 -0
  135. package/src/docs/requests.ts +39 -0
  136. package/src/docs/snapshot.chunk.ts +8 -0
  137. package/src/docs/snapshot.json +7416 -0
  138. package/src/docs/topics.ts +216 -0
  139. package/src/i18n/es.ts +61 -4
  140. package/src/i18n/ja.ts +61 -4
  141. package/src/i18n/ko.ts +61 -4
  142. package/src/i18n/zh-cn.ts +61 -4
  143. package/src/i18n/zh-tw.ts +61 -4
  144. package/src/layout/desks.ts +1 -1
  145. package/src/layout/pane-manager/dock-tree.ts +18 -0
  146. package/src/layout/pane-manager/index.ts +1 -0
  147. package/src/market-data/coordinator/chart.ts +10 -4
  148. package/src/market-data/coordinator/index.ts +6 -3
  149. package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
  150. package/src/market-data/futures-contract.ts +151 -0
  151. package/src/market-data/hooks.tsx +10 -2
  152. package/src/market-data/market/format.ts +39 -21
  153. package/src/market-data/market/freshness.ts +81 -18
  154. package/src/market-data/market/status.ts +19 -23
  155. package/src/market-data/published-apac-sessions.ts +23 -1
  156. package/src/market-data/quotes/contributions.ts +3 -0
  157. package/src/market-data/quotes/metadata.ts +7 -24
  158. package/src/market-data/quotes/resolution.ts +2 -0
  159. package/src/market-data/quotes/screener-live-quotes.ts +5 -4
  160. package/src/market-data/result-types.ts +2 -0
  161. package/src/plugins/builtin/account-management/model.ts +1 -56
  162. package/src/plugins/builtin/account-management/pane.tsx +6 -4
  163. package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
  164. package/src/plugins/builtin/alerts/cli.ts +313 -47
  165. package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
  166. package/src/plugins/builtin/alerts/events.ts +23 -2
  167. package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
  168. package/src/plugins/builtin/alerts/history.ts +2 -0
  169. package/src/plugins/builtin/alerts/index.tsx +41 -9
  170. package/src/plugins/builtin/alerts/pane.tsx +8 -0
  171. package/src/plugins/builtin/alerts/research-builder.ts +8 -3
  172. package/src/plugins/builtin/alerts/research-rules.ts +18 -2
  173. package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
  174. package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
  175. package/src/plugins/builtin/alerts/scheduled.ts +254 -0
  176. package/src/plugins/builtin/alerts/targets.ts +92 -0
  177. package/src/plugins/builtin/analytics/index.tsx +4 -2
  178. package/src/plugins/builtin/analytics/risk-headless.ts +30 -12
  179. package/src/plugins/builtin/analytics/risk-math.ts +91 -27
  180. package/src/plugins/builtin/analytics/risk-model.ts +35 -5
  181. package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
  182. package/src/plugins/builtin/attention/index.tsx +2 -0
  183. package/src/plugins/builtin/attention/pane.tsx +3 -1
  184. package/src/plugins/builtin/attention/series.ts +26 -0
  185. package/src/plugins/builtin/awards/index.tsx +2 -0
  186. package/src/plugins/builtin/awards/pane.tsx +3 -1
  187. package/src/plugins/builtin/awards/series.ts +29 -0
  188. package/src/plugins/builtin/bond-calculator/model.ts +2 -1
  189. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  190. package/src/plugins/builtin/cds/client.ts +70 -13
  191. package/src/plugins/builtin/cds/headless.ts +116 -19
  192. package/src/plugins/builtin/cds/index.tsx +3 -1
  193. package/src/plugins/builtin/cds/model.ts +193 -31
  194. package/src/plugins/builtin/cds/pane.tsx +56 -14
  195. package/src/plugins/builtin/cds/series.ts +19 -0
  196. package/src/plugins/builtin/central-bank-rates/index.tsx +2 -0
  197. package/src/plugins/builtin/central-bank-rates/series.ts +42 -0
  198. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +192 -255
  199. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
  200. package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
  201. package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
  202. package/src/plugins/builtin/chart-composer/headless.ts +8 -3
  203. package/src/plugins/builtin/chart-composer/index.tsx +9 -2
  204. package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
  205. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
  206. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
  207. package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
  208. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
  209. package/src/plugins/builtin/chat/controller/index.ts +2 -0
  210. package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
  211. package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
  212. package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
  213. package/src/plugins/builtin/cloud/askg/model.ts +27 -8
  214. package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
  215. package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
  216. package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
  217. package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
  218. package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
  219. package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
  220. package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
  221. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
  222. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
  223. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
  224. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
  225. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
  226. package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
  227. package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
  228. package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
  229. package/src/plugins/builtin/company-attention/headless.ts +19 -5
  230. package/src/plugins/builtin/company-attention/index.tsx +2 -0
  231. package/src/plugins/builtin/company-attention/model.ts +26 -7
  232. package/src/plugins/builtin/company-attention/pane.tsx +12 -9
  233. package/src/plugins/builtin/company-attention/series.ts +52 -0
  234. package/src/plugins/builtin/company-kpis/pane.tsx +4 -2
  235. package/src/plugins/builtin/composite-plugins.ts +19 -13
  236. package/src/plugins/builtin/cot/index.tsx +3 -1
  237. package/src/plugins/builtin/cot/model.ts +40 -11
  238. package/src/plugins/builtin/cot/series.ts +27 -0
  239. package/src/plugins/builtin/credit-boards/index.tsx +2 -0
  240. package/src/plugins/builtin/credit-boards/series.ts +66 -0
  241. package/src/plugins/builtin/credit-conditions/index.tsx +2 -0
  242. package/src/plugins/builtin/credit-conditions/series.ts +26 -0
  243. package/src/plugins/builtin/credit-documents/headless.ts +31 -1
  244. package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
  245. package/src/plugins/builtin/crypto-board/headless.ts +2 -3
  246. package/src/plugins/builtin/crypto-board/index.tsx +2 -0
  247. package/src/plugins/builtin/crypto-board/model.ts +12 -0
  248. package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
  249. package/src/plugins/builtin/crypto-board/series.ts +48 -0
  250. package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
  251. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  252. package/src/plugins/builtin/debt-maturities/series.ts +45 -0
  253. package/src/plugins/builtin/dividend-yield/headless.ts +2 -2
  254. package/src/plugins/builtin/dividend-yield/index.tsx +2 -0
  255. package/src/plugins/builtin/dividend-yield/series.ts +20 -0
  256. package/src/plugins/builtin/docs/blocks.tsx +181 -0
  257. package/src/plugins/builtin/docs/index.tsx +68 -0
  258. package/src/plugins/builtin/docs/pane.tsx +426 -0
  259. package/src/plugins/builtin/docs/targets.ts +72 -0
  260. package/src/plugins/builtin/docs/use-docs.ts +60 -0
  261. package/src/plugins/builtin/doe/index.tsx +2 -0
  262. package/src/plugins/builtin/doe/series.ts +62 -0
  263. package/src/plugins/builtin/earnings/client.ts +3 -2
  264. package/src/plugins/builtin/earnings/format.ts +1 -5
  265. package/src/plugins/builtin/earnings/headless.ts +58 -6
  266. package/src/plugins/builtin/earnings/history-model.ts +15 -1
  267. package/src/plugins/builtin/earnings/history-table.ts +13 -2
  268. package/src/plugins/builtin/earnings/history.tsx +7 -3
  269. package/src/plugins/builtin/econ/fred-catalog.ts +189 -0
  270. package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
  271. package/src/plugins/builtin/econ/index.tsx +2 -0
  272. package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
  273. package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
  274. package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
  275. package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
  276. package/src/plugins/builtin/exposure/holdings.ts +1 -1
  277. package/src/plugins/builtin/exposure/pane.tsx +3 -1
  278. package/src/plugins/builtin/fear-greed/index.tsx +4 -0
  279. package/src/plugins/builtin/fear-greed/series.ts +52 -0
  280. package/src/plugins/builtin/futures/index.tsx +43 -3
  281. package/src/plugins/builtin/futures/model.ts +1 -1
  282. package/src/plugins/builtin/futures/returns.ts +1 -1
  283. package/src/plugins/builtin/futures/series.ts +13 -0
  284. package/src/plugins/builtin/futures/table.tsx +1 -1
  285. package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
  286. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  287. package/src/plugins/builtin/futures-curve/headless.ts +70 -9
  288. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  289. package/src/plugins/builtin/futures-curve/model.ts +66 -11
  290. package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
  291. package/src/plugins/builtin/fx-matrix/index.tsx +1 -1
  292. package/src/plugins/builtin/gpu/board.tsx +13 -10
  293. package/src/plugins/builtin/gpu/changes.tsx +4 -4
  294. package/src/plugins/builtin/gpu/client.ts +19 -1
  295. package/src/plugins/builtin/gpu/equities.tsx +14 -10
  296. package/src/plugins/builtin/gpu/headless.ts +56 -25
  297. package/src/plugins/builtin/gpu/history.tsx +3 -3
  298. package/src/plugins/builtin/gpu/index.tsx +2 -0
  299. package/src/plugins/builtin/gpu/model.ts +101 -16
  300. package/src/plugins/builtin/gpu/pane.tsx +28 -12
  301. package/src/plugins/builtin/gpu/series.ts +38 -0
  302. package/src/plugins/builtin/help/function-card.tsx +25 -6
  303. package/src/plugins/builtin/help/index.tsx +17 -8
  304. package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
  305. package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
  306. package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
  307. package/src/plugins/builtin/holders/client.ts +22 -3
  308. package/src/plugins/builtin/holders/format.ts +18 -3
  309. package/src/plugins/builtin/holders/headless.ts +36 -133
  310. package/src/plugins/builtin/holders/pane.tsx +11 -4
  311. package/src/plugins/builtin/holders/report-header.ts +40 -5
  312. package/src/plugins/builtin/holders/report-rows.ts +240 -0
  313. package/src/plugins/builtin/insider/client.ts +35 -20
  314. package/src/plugins/builtin/insider/headless.ts +41 -11
  315. package/src/plugins/builtin/insider/index.tsx +26 -9
  316. package/src/plugins/builtin/insider/insider-data.ts +10 -0
  317. package/src/plugins/builtin/insider/issuer.ts +49 -0
  318. package/src/plugins/builtin/insider/model.ts +3 -0
  319. package/src/plugins/builtin/iv-history/client.ts +14 -4
  320. package/src/plugins/builtin/iv-history/headless.ts +7 -4
  321. package/src/plugins/builtin/iv-history/index.tsx +2 -0
  322. package/src/plugins/builtin/iv-history/model.ts +111 -7
  323. package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
  324. package/src/plugins/builtin/iv-history/series.ts +29 -0
  325. package/src/plugins/builtin/jobs/headless.ts +28 -3
  326. package/src/plugins/builtin/jobs/index.tsx +3 -1
  327. package/src/plugins/builtin/jobs/series.ts +19 -0
  328. package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
  329. package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
  330. package/src/plugins/builtin/macro-day/client.ts +44 -3
  331. package/src/plugins/builtin/macro-day/headless.ts +13 -10
  332. package/src/plugins/builtin/macro-day/model.ts +56 -10
  333. package/src/plugins/builtin/macro-day/pane.tsx +30 -20
  334. package/src/plugins/builtin/market-heatmap/model.ts +19 -11
  335. package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
  336. package/src/plugins/builtin/market-movers/client.ts +7 -5
  337. package/src/plugins/builtin/market-movers/index.tsx +3 -2
  338. package/src/plugins/builtin/market-movers/model.ts +30 -0
  339. package/src/plugins/builtin/market-movers/screener.ts +31 -0
  340. package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
  341. package/src/plugins/builtin/market-valuation/index.tsx +3 -3
  342. package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
  343. package/src/plugins/builtin/members/headless.ts +7 -2
  344. package/src/plugins/builtin/members/model.ts +31 -3
  345. package/src/plugins/builtin/members/pane.tsx +3 -6
  346. package/src/plugins/builtin/mna/headless.ts +15 -3
  347. package/src/plugins/builtin/money-markets/index.tsx +2 -0
  348. package/src/plugins/builtin/money-markets/series.ts +41 -0
  349. package/src/plugins/builtin/notes/cli.ts +12 -7
  350. package/src/plugins/builtin/options/view.tsx +1 -1
  351. package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
  352. package/src/plugins/builtin/options-positioning/client.ts +7 -3
  353. package/src/plugins/builtin/options-positioning/headless.ts +1 -0
  354. package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
  355. package/src/plugins/builtin/options-scenario/client.ts +2 -1
  356. package/src/plugins/builtin/options-scenario/headless.ts +1 -0
  357. package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
  358. package/src/plugins/builtin/perps/client.ts +40 -6
  359. package/src/plugins/builtin/perps/equity-row.tsx +33 -11
  360. package/src/plugins/builtin/perps/freshness.ts +66 -0
  361. package/src/plugins/builtin/perps/headless.ts +45 -30
  362. package/src/plugins/builtin/perps/index.tsx +18 -1
  363. package/src/plugins/builtin/perps/model.ts +20 -5
  364. package/src/plugins/builtin/perps/pane.tsx +76 -20
  365. package/src/plugins/builtin/perps/series.ts +76 -0
  366. package/src/plugins/builtin/plugin-marketplace/pane.tsx +67 -61
  367. package/src/plugins/builtin/plugin-module.ts +3 -0
  368. package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
  369. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +273 -0
  370. package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
  371. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +331 -65
  372. package/src/plugins/builtin/portfolio-list/cli/render.ts +200 -31
  373. package/src/plugins/builtin/portfolio-list/cli/shared.ts +24 -0
  374. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -47
  375. package/src/plugins/builtin/portfolio-list/column-values.ts +1 -1
  376. package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
  377. package/src/plugins/builtin/portfolio-list/headless.ts +34 -4
  378. package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
  379. package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
  380. package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -1
  381. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +17 -1
  382. package/src/plugins/builtin/portfolio-list/summary/totals.ts +1 -1
  383. package/src/plugins/builtin/portfolio-list/table.tsx +7 -1
  384. package/src/plugins/builtin/power/client.ts +16 -0
  385. package/src/plugins/builtin/power/evidence.ts +6 -2
  386. package/src/plugins/builtin/power/headless.ts +71 -7
  387. package/src/plugins/builtin/power/index.tsx +4 -1
  388. package/src/plugins/builtin/power/model.ts +72 -1
  389. package/src/plugins/builtin/power/pane.tsx +32 -9
  390. package/src/plugins/builtin/rate-path/headless.ts +11 -3
  391. package/src/plugins/builtin/realized-vol/headless.ts +5 -0
  392. package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
  393. package/src/plugins/builtin/research/event-model.ts +68 -24
  394. package/src/plugins/builtin/research/events-headless.ts +2 -1
  395. package/src/plugins/builtin/research/headless.ts +2 -1
  396. package/src/plugins/builtin/seasonality/client.ts +15 -7
  397. package/src/plugins/builtin/seasonality/headless.ts +36 -12
  398. package/src/plugins/builtin/seasonality/index.tsx +2 -2
  399. package/src/plugins/builtin/seasonality/model.ts +119 -0
  400. package/src/plugins/builtin/seasonality/pane.tsx +108 -37
  401. package/src/plugins/builtin/series-inventory.ts +91 -0
  402. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
  403. package/src/plugins/builtin/shared/command-tab.ts +30 -12
  404. package/src/plugins/builtin/shared/earnings-report.ts +55 -0
  405. package/src/plugins/builtin/shared/fred-points.ts +20 -0
  406. package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
  407. package/src/plugins/builtin/shared/open-description.ts +29 -0
  408. package/src/plugins/builtin/shared/report-freshness.ts +9 -0
  409. package/src/plugins/builtin/shared/series-warning.ts +5 -0
  410. package/src/plugins/builtin/short-interest/headless.ts +1 -0
  411. package/src/plugins/builtin/short-interest/index.tsx +2 -0
  412. package/src/plugins/builtin/short-interest/series.ts +36 -0
  413. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  414. package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
  415. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  416. package/src/plugins/builtin/short-volume/index.tsx +2 -0
  417. package/src/plugins/builtin/short-volume/series.ts +23 -0
  418. package/src/plugins/builtin/social-mentions/index.tsx +2 -0
  419. package/src/plugins/builtin/social-mentions/series.ts +23 -0
  420. package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
  421. package/src/plugins/builtin/supply-chain/pane.tsx +3 -1
  422. package/src/plugins/builtin/thirteenf/api.ts +1 -0
  423. package/src/plugins/builtin/thirteenf/data.ts +6 -4
  424. package/src/plugins/builtin/thirteenf/headless.ts +217 -36
  425. package/src/plugins/builtin/thirteenf/model.ts +39 -1
  426. package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
  427. package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
  428. package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
  429. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  430. package/src/plugins/builtin/ticker-detail/index.tsx +3 -0
  431. package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
  432. package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
  433. package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
  434. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
  435. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +48 -4
  436. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
  437. package/src/plugins/builtin/time-sales/headless.ts +1 -0
  438. package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
  439. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  440. package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
  441. package/src/plugins/builtin/vol-surface/headless.ts +1 -0
  442. package/src/plugins/builtin/volatility/index.tsx +2 -0
  443. package/src/plugins/builtin/volatility/series.ts +84 -0
  444. package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
  445. package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
  446. package/src/plugins/builtin/world-venue-map/index.ts +2 -1
  447. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +8 -4
  448. package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
  449. package/src/plugins/builtin/yield-curve/chart.ts +2 -2
  450. package/src/plugins/builtin/yield-curve/curves.ts +21 -8
  451. package/src/plugins/builtin/yield-curve/headless.ts +71 -18
  452. package/src/plugins/builtin/yield-curve/index.tsx +3 -1
  453. package/src/plugins/builtin/yield-curve/series.ts +86 -0
  454. package/src/plugins/catalog-browser.ts +2 -1
  455. package/src/plugins/registry/index.ts +89 -4
  456. package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
  457. package/src/portfolio/position-value.ts +40 -0
  458. package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
  459. package/src/public/time-series.ts +17 -0
  460. package/src/react/auto-refresh.ts +13 -3
  461. package/src/remote/app-host.tsx +20 -4
  462. package/src/remote/confirm-change.tsx +85 -0
  463. package/src/remote/controller-utils.ts +8 -1
  464. package/src/remote/controller.ts +123 -6
  465. package/src/remote/pane-screenshot.ts +47 -0
  466. package/src/remote/schema.ts +62 -0
  467. package/src/remote/types.ts +30 -0
  468. package/src/remote/watchlist.ts +306 -0
  469. package/src/renderers/browser/main.tsx +3 -2
  470. package/src/renderers/cloudflare/worker.ts +1 -1
  471. package/src/renderers/dom/data-table/frozen-column.ts +3 -1
  472. package/src/renderers/dom/data-table/index.tsx +33 -6
  473. package/src/renderers/dom/data-table/row.tsx +27 -1
  474. package/src/renderers/dom/desktop/control-styles.ts +63 -1
  475. package/src/renderers/dom/desktop/controls.tsx +30 -23
  476. package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
  477. package/src/renderers/dom/desktop/icons.tsx +7 -0
  478. package/src/renderers/dom/dom-ui-host.tsx +3 -0
  479. package/src/renderers/dom/host/box.tsx +3 -0
  480. package/src/renderers/dom/host/chart-surface.tsx +6 -2
  481. package/src/renderers/dom/host/live-frame.ts +6 -2
  482. package/src/renderers/dom/host/overflow-fade.ts +14 -1
  483. package/src/renderers/dom/host/size-observer.ts +26 -0
  484. package/src/renderers/dom/host/surface-3d.tsx +7 -2
  485. package/src/renderers/dom/host/text.tsx +1 -1
  486. package/src/renderers/dom/styles.css +61 -0
  487. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +17 -2
  488. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +19 -11
  489. package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
  490. package/src/renderers/electrobun/view/main.tsx +2 -0
  491. package/src/series/capability.ts +75 -0
  492. package/src/series/csv.ts +160 -0
  493. package/src/series/files.ts +107 -0
  494. package/src/series/registry.ts +198 -0
  495. package/src/series/resolve.ts +107 -0
  496. package/src/series/standalone.ts +48 -0
  497. package/src/series/types.ts +145 -0
  498. package/src/series/validate.ts +171 -0
  499. package/src/sources/gloomberb-cloud/index.ts +7 -7
  500. package/src/sources/gloomberb-cloud/normalizers.ts +1 -0
  501. package/src/sources/history-result.ts +1 -0
  502. package/src/sources/listing-symbols.ts +4 -1
  503. package/src/sources/provider-router/batches.ts +4 -1
  504. package/src/sources/provider-router/cache.ts +4 -2
  505. package/src/sources/provider-router/cached-routes.ts +1 -1
  506. package/src/sources/provider-router/financial-routes.ts +1 -0
  507. package/src/sources/provider-router/financials.ts +13 -0
  508. package/src/sources/provider-router/history.ts +43 -25
  509. package/src/sources/provider-router/search.ts +1 -0
  510. package/src/sync/core-contributors.ts +1 -0
  511. package/src/tickers/company-name.ts +75 -0
  512. package/src/tickers/instrument-kind.ts +25 -0
  513. package/src/tickers/open-target.ts +3 -2
  514. package/src/tickers/search/index.ts +45 -7
  515. package/src/tickers/search/ranking.ts +33 -17
  516. package/src/tickers/search/types.ts +7 -1
  517. package/src/tickers/us-listing.ts +34 -0
  518. package/src/time-series/hooks.ts +9 -0
  519. package/src/time-series/resolve.ts +95 -16
  520. package/src/time-series/types.ts +4 -2
  521. package/src/time-series/use-chart-resolution.ts +32 -0
  522. package/src/types/config.ts +6 -0
  523. package/src/types/data-provider.ts +5 -0
  524. package/src/types/financials.ts +52 -1
  525. package/src/types/headless.ts +61 -0
  526. package/src/types/plugin.ts +19 -0
  527. package/src/types/price-history.ts +7 -0
  528. package/src/types/ticker.ts +14 -0
  529. package/src/ui/host.tsx +18 -0
  530. package/src/ui/live-resize.ts +81 -0
  531. package/src/ui/live-stretch.ts +121 -0
  532. package/src/ui/measured-cells.ts +58 -0
  533. package/src/ui/pane-fill.ts +11 -0
  534. package/src/utils/basis-points.ts +17 -0
  535. package/src/utils/cli-output.ts +7 -1
  536. package/src/utils/concurrency.ts +25 -0
  537. package/src/utils/crypto-pair.ts +20 -0
  538. package/src/utils/currency-pair.ts +19 -0
  539. package/src/utils/decimal-comma.ts +19 -0
  540. package/src/utils/dom-screenshot-css.ts +265 -0
  541. package/src/utils/dom-screenshot-rasters.ts +276 -0
  542. package/src/utils/dom-screenshot.ts +437 -52
  543. package/src/utils/exchange-rate-snapshot.ts +6 -2
  544. package/src/utils/exchanges.ts +107 -1
  545. package/src/utils/format.ts +16 -3
  546. package/src/utils/fundamentals.ts +66 -0
  547. package/src/utils/futures-generic.ts +6 -12
  548. package/src/utils/fx-market-hours.ts +15 -5
  549. package/src/utils/price-history.ts +99 -42
  550. package/src/utils/sec-eps-basis.ts +24 -11
  551. package/src/utils/sec.ts +61 -7
  552. package/src/utils/utc-time.ts +51 -4
  553. package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
  554. /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
@@ -45,6 +45,7 @@ import {
45
45
  } from "../../../api-client/equity-screener";
46
46
  import type { PaneProps } from "../../../types/plugin";
47
47
  import { formatPercentileRank } from "../../../utils/format";
48
+ import { useOpenDescription } from "../shared/open-description";
48
49
  import { useResearchCloudSession } from "../shared/research-cloud-session";
49
50
  import { INITIAL_STREAM_RANGE, streamWindowRows } from "../shared/use-quote-board";
50
51
  import { usePlanAccess } from "../../../api-client/plan-access";
@@ -205,7 +206,8 @@ function EquityScreenView({
205
206
  const colors = useThemeColors(),
206
207
  dialog = useDialog(),
207
208
  host = useRendererHost();
208
- const { notify, createPaneFromTemplate } = usePluginAppActions();
209
+ const { notify } = usePluginAppActions();
210
+ const openDescription = useOpenDescription();
209
211
  const session = useResearchCloudSession(),
210
212
  access = usePlanAccess();
211
213
  const [definition, setDefinition] = usePluginPaneState("definition", initial);
@@ -314,16 +316,7 @@ function EquityScreenView({
314
316
  setActionError(null);
315
317
  };
316
318
  const research = () => {
317
- if (selected)
318
- createPaneFromTemplate("new-ticker-detail-pane", {
319
- symbol: selected.symbol,
320
- listing: {
321
- name: selected.name ?? selected.symbol,
322
- exchange: selected.exchange,
323
- currency: selected.currency ?? "",
324
- type: "STK",
325
- },
326
- });
319
+ if (selected) openDescription(selected.symbol, selected.exchange);
327
320
  };
328
321
  const startSave = () => {
329
322
  if (!access.emailVerified) { switchMode("saved"); return; }
@@ -4,7 +4,7 @@ import type { Portfolio, TickerRecord } from "../../../types/ticker";
4
4
  import { publicTickerKey } from "../../../utils/exchanges";
5
5
  import { resolveCurrencyUnit } from "../../../utils/currency-units";
6
6
  import { convertCurrency } from "../../../utils/format";
7
- import { getPortfolioPositionMetrics, getPortfolioQuoteDisplay, resolvePortfolioMarketValue } from "../portfolio-list/position-metrics";
7
+ import { getPortfolioPositionMetrics, getPortfolioQuoteDisplay, resolvePortfolioMarketValue } from "../../../portfolio/position-metrics";
8
8
 
9
9
  /** Explicit NAV preserves cash, shorts and leverage; net holdings are never used as NAV. */
10
10
  export async function portfolioHoldings(portfolio: Portfolio, tickers: TickerRecord[], nav: number, market: Pick<DataProvider, "getQuote" | "getExchangeRate">): Promise<ExposureHolding[]> {
@@ -10,6 +10,7 @@ import type { PaneProps } from "../../../types/plugin";
10
10
  import { Box, ScrollBox, Text, useRendererHost, useUiCapabilities } from "../../../ui";
11
11
  import { SignInWall } from "../cloud/auth-actions";
12
12
  import { CLOUD_PLAN_KEY, useCloudUpgradeAction } from "../shared/cloud-upgrade";
13
+ import { useOpenDescription } from "../shared/open-description";
13
14
  import { Blurred, LockedOverlay, UpgradeLabel } from "../shared/locked-rows";
14
15
  import { humanLabel, listingCell, missingCell } from "../shared/research-cells";
15
16
  import { isCloudSessionRequired, useResearchCloudSession } from "../shared/research-cloud-session";
@@ -79,6 +80,7 @@ export function ExposurePane({ width, height, focused }: PaneProps) {
79
80
  const accessKey = `${session.requestKey}:${access.hasProAccess ? "full" : "preview"}`;
80
81
  const upgrade = useCloudUpgradeAction("expo");
81
82
  const { createPaneFromTemplate } = usePluginAppActions();
83
+ const openDescription = useOpenDescription();
82
84
  const [openingScenario] = usePaneSettingValue("scenario", "taiwan-disruption");
83
85
  const [customSetting] = usePaneSettingValue("customScenario", "");
84
86
  const [openingDepth] = usePaneSettingValue("depth", 2);
@@ -150,7 +152,7 @@ export function ExposurePane({ width, height, focused }: PaneProps) {
150
152
  ...(symbol ? [
151
153
  ...(activeRow?.driver ? [{ id: "dataset", key: "a", label: "ll disclosures", title: "Open company disclosures", onPress: () => createPaneFromTemplate(activeRow.driver!.kind === "kpi" ? "company-kpis-pane" : activeRow.driver!.kind === "guidance" ? "company-guidance-pane" : "credit-documents-pane", { symbol }) }] : []),
152
154
  { id: "supply", key: "c", label: "hain", title: "Supply chain", onPress: () => createPaneFromTemplate("supply-chain-pane", { symbol }) },
153
- { id: "des", key: "d", label: "es", onPress: () => createPaneFromTemplate("new-ticker-detail-pane", { symbol }) },
155
+ { id: "des", key: "d", label: "es", onPress: () => openDescription(symbol) },
154
156
  { id: "fa", key: "f", label: "a", onPress: () => createPaneFromTemplate("financial-analysis-pane", { symbol }) },
155
157
  { id: "chart", key: "g", label: "raph", onPress: () => createPaneFromTemplate("chart-composer-pane", { arg: symbol }) },
156
158
  ] : []),
@@ -7,6 +7,7 @@ import {
7
7
  } from "./cache";
8
8
  import { FearGreedPane } from "./pane";
9
9
  import { fearGreedHeadless } from "./headless";
10
+ import { FEAR_GREED_SERIES } from "./series";
10
11
 
11
12
  export const fearGreedPlugin: GloomPlugin = {
12
13
  id: "fear-greed",
@@ -29,6 +30,9 @@ export const fearGreedPlugin: GloomPlugin = {
29
30
  resetFearGreedPersistence();
30
31
  },
31
32
 
33
+ // The index and its seven readings, chartable against anything else.
34
+ series: FEAR_GREED_SERIES,
35
+
32
36
  panes: [
33
37
  {
34
38
  id: "fear-greed",
@@ -0,0 +1,52 @@
1
+ import type { SeriesDefinition, SeriesLoadResult, SeriesPoint } from "../../../series/types";
2
+ import { cachedSeriesWarning } from "../shared/series-warning";
3
+ import { loadFearGreed } from "./cache";
4
+ import type { FearGreedData } from "./data";
5
+
6
+ /** The index refreshes through the session; the pane's cache keeps a copy for five minutes. */
7
+ const REFRESH_MS = 5 * 60_000;
8
+
9
+ type Reading = (data: FearGreedData) => SeriesPoint[];
10
+
11
+ function component(id: string, pick: "primary" | "secondary"): Reading {
12
+ return (data) => {
13
+ const indicator = data.indicators.find((entry) => entry.definition.id === id);
14
+ if (!indicator) throw new Error("This component is missing from the latest reading.");
15
+ if (pick === "primary") return indicator.points.map((point) => ({ date: point.date, value: point.close }));
16
+ return indicator.secondaryPoints.flatMap((point) => {
17
+ const date = indicator.points[point.index]?.date;
18
+ return date ? [{ date, value: point.value }] : [];
19
+ });
20
+ };
21
+ }
22
+
23
+ function series(id: string, name: string, unit: string, read: Reading, tags: readonly string[]): SeriesDefinition {
24
+ return {
25
+ id: `fear-greed:${id}`,
26
+ name,
27
+ unit,
28
+ frequency: "daily",
29
+ group: "Sentiment",
30
+ tags: ["fear and greed", ...tags],
31
+ refreshMs: REFRESH_MS,
32
+ load: async (): Promise<SeriesLoadResult> => {
33
+ const result = await loadFearGreed();
34
+ const warning = cachedSeriesWarning(result);
35
+ return { points: read(result.data), ...(warning ? { warning } : {}) };
36
+ },
37
+ };
38
+ }
39
+
40
+ /** The index and the seven readings it is built from, as the pane charts them. */
41
+ export const FEAR_GREED_SERIES: readonly SeriesDefinition[] = [
42
+ series("index", "Fear & Greed index", "score", (data) => data.overall.history.map((point) => ({ date: point.date, value: point.close })), ["sentiment"]),
43
+ series("market-momentum", "Fear & Greed: S&P 500 momentum", "index", component("market-momentum", "primary"), ["momentum", "S&P 500"]),
44
+ series("market-momentum-average", "Fear & Greed: S&P 500 125-day average", "index", component("market-momentum", "secondary"), ["momentum", "moving average"]),
45
+ series("stock-price-strength", "Fear & Greed: net new 52-week highs", "%", component("stock-price-strength", "primary"), ["breadth", "highs and lows"]),
46
+ series("stock-price-breadth", "Fear & Greed: McClellan volume summation", "index", component("stock-price-breadth", "primary"), ["breadth", "McClellan"]),
47
+ series("put-call-options", "Fear & Greed: 5-day put/call ratio", "ratio", component("put-call-options", "primary"), ["options", "put call"]),
48
+ series("market-volatility", "Fear & Greed: VIX", "index", component("market-volatility", "primary"), ["volatility", "VIX"]),
49
+ series("market-volatility-average", "Fear & Greed: VIX 50-day average", "index", component("market-volatility", "secondary"), ["volatility", "moving average"]),
50
+ series("safe-haven-demand", "Fear & Greed: stocks minus bonds, 20-day return", "%", component("safe-haven-demand", "primary"), ["safe haven", "bonds"]),
51
+ series("junk-bond-demand", "Fear & Greed: junk bond spread", "%", component("junk-bond-demand", "primary"), ["credit", "high yield", "junk"]),
52
+ ];
@@ -13,6 +13,7 @@ import {
13
13
  type PaneFooterSegment,
14
14
  } from "../../../components";
15
15
  import { handleRefreshKey } from "../../../components/data-table/table-pane";
16
+ import { useRemoteUiNode } from "../../../remote/semantic-tree";
16
17
  import { usePaneVisible } from "../../../state/app/activity";
17
18
  import { usePaneInstance } from "../../../state/app/context";
18
19
  import { TICKER_RESEARCH_PANE_ID } from "../../../types/config";
@@ -22,7 +23,9 @@ import { isPlainArrowUp, stopSearchFocusNavigation } from "../../../utils/search
22
23
  import { cycleSortPreference, nextHeaderSort } from "../../../utils/sort-values";
23
24
  import { useAssetData, usePluginTickerActions } from "../../runtime";
24
25
  import type { PluginModule } from "../plugin-module";
26
+ import { FUTURES_SERIES } from "./series";
25
27
  import { useLiveStreamingSetting } from "../../../state/hooks/live-streaming";
28
+ import { quoteObservation } from "../shared/report-freshness";
26
29
  import {
27
30
  boardErrorMessage,
28
31
  quoteBoardFooterInfo,
@@ -34,9 +37,10 @@ import {
34
37
  import {
35
38
  FUTURES_CONTRACTS,
36
39
  FUTURES_SECTOR_LABELS,
40
+ futuresBoardContract,
37
41
  getContractsBySector,
38
42
  type FuturesSector,
39
- } from "./contracts";
43
+ } from "../../../market-data/futures-board";
40
44
  import {
41
45
  buildFuturesRows,
42
46
  DEFAULT_FUTURES_SORT,
@@ -75,7 +79,8 @@ function FuturesPane({ focused, width, height }: PaneProps) {
75
79
  const liveStreaming = useLiveStreamingSetting();
76
80
  const [selectedId, setSelectedId] = useState<string | null>(null);
77
81
  const [sortPreference, setSortPreference] = useState<FuturesSortPreference>(DEFAULT_FUTURES_SORT);
78
- const [searchQuery, setSearchQuery] = useState("");
82
+ // `FUT TTF` opens the board searched for the contract it names.
83
+ const [searchQuery, setSearchQuery] = useState(() => paneInstance?.params?.query ?? "");
79
84
  const { active: searchFocused, focus: focusSearch, searchProps } = useQueryBarSearch();
80
85
  const [collapsedSectors, setCollapsedSectors] = useState<ReadonlySet<FuturesSector>>(new Set());
81
86
  const [visibleRange, setVisibleRange] = useState<DataTableVisibleRange | null>(null);
@@ -196,6 +201,17 @@ function FuturesPane({ focused, width, height }: PaneProps) {
196
201
  return handlePaneKey(event);
197
202
  }, [focusSearch, handlePaneKey]);
198
203
 
204
+ // `fn FUT` and `shot FUT` are dated by the quotes the board shows, as `quote` dates them:
205
+ // the newest, its delay, and whether the markets are open.
206
+ useRemoteUiNode(quotes.size > 0 ? {
207
+ role: "report-freshness",
208
+ label: "Quote freshness",
209
+ getMetadata: () => {
210
+ const now = Date.now();
211
+ return { observations: [...quotes.values()].flatMap((state) => (state.quote ? [quoteObservation(state.quote, now)] : [])) };
212
+ },
213
+ } : null);
214
+
199
215
  const status = quoteBoardStatus(quotes);
200
216
  const errorMessage = boardErrorMessage(quotes);
201
217
  // Every load came back empty: a board of dashes reads as broken, so the
@@ -265,6 +281,7 @@ function FuturesPane({ focused, width, height }: PaneProps) {
265
281
  renderSectionHeader={renderSectorHeader}
266
282
  renderCell={renderCell}
267
283
  selectedTextOverridesCellColor
284
+ reportEveryRow
268
285
  emptyStateTitle={searchQuery.trim()
269
286
  ? "No matching contracts."
270
287
  : "No market data provider connected."}
@@ -288,6 +305,7 @@ function FuturesPane({ focused, width, height }: PaneProps) {
288
305
  }
289
306
 
290
307
  export const futuresModule: PluginModule = {
308
+ series: FUTURES_SERIES,
291
309
  panes: [
292
310
  {
293
311
  id: FUTURES_PANE_ID,
@@ -298,6 +316,7 @@ export const futuresModule: PluginModule = {
298
316
  defaultMode: "floating",
299
317
  defaultFloatingSize: { width: 76, height: 34 },
300
318
  tableExport: true,
319
+ shotFitsRows: true,
301
320
  // Resolved per open so the dialog shows the full default set until the
302
321
  // user saves a narrower selection.
303
322
  settings: (context) => ({
@@ -341,11 +360,32 @@ export const futuresModule: PluginModule = {
341
360
  "lumber",
342
361
  "aluminum",
343
362
  "ttf",
363
+ "energy",
364
+ "natural gas",
365
+ "gas",
366
+ "lng",
367
+ "brent",
368
+ "wti",
369
+ "heating oil",
370
+ "gasoline",
344
371
  "treasuries",
345
372
  "contracts",
346
373
  "cme",
347
374
  ],
348
- shortcut: { prefix: "FUT", aliases: ["GLCO"] },
375
+ shortcut: {
376
+ prefix: "FUT",
377
+ aliases: ["GLCO"],
378
+ argKind: "text",
379
+ argPlaceholder: "code or name",
380
+ argOptional: true,
381
+ },
382
+ // A board code or symbol searches for that contract alone (NG=F: a bare NG also matches Orange Juice); other text searches as typed.
383
+ createInstance: (_context, options) => {
384
+ const input = options?.arg?.trim();
385
+ if (!input) return {};
386
+ const query = futuresBoardContract(input)?.symbol ?? input;
387
+ return { title: `FUT ${input.toUpperCase()}`, params: { query } };
388
+ },
349
389
  },
350
390
  ],
351
391
  };
@@ -1,7 +1,7 @@
1
1
  import type { Quote } from "../../../types/financials";
2
2
  import { compareSortValues, type SortDirection } from "../../../utils/sort-values";
3
3
  import type { BoardQuoteMap } from "../shared/use-quote-board";
4
- import { FUTURES_SECTOR_ORDER, type FuturesContract, type FuturesSector } from "./contracts";
4
+ import { FUTURES_SECTOR_ORDER, type FuturesContract, type FuturesSector } from "../../../market-data/futures-board";
5
5
  import type { FuturesReturnHorizon } from "./returns";
6
6
  import type { FrontReturnsMap } from "./use-front-returns";
7
7
 
@@ -1,6 +1,6 @@
1
1
  import type { PricePoint, Quote } from "../../../types/financials";
2
2
  import { calendarMonthsBefore } from "../../../utils/calendar-date";
3
- import type { FuturesContract } from "./contracts";
3
+ import type { FuturesContract } from "../../../market-data/futures-board";
4
4
  import { quotedContractMonth } from "./model";
5
5
 
6
6
  export type FuturesReturnHorizon = "1W" | "1M" | "YTD";
@@ -0,0 +1,13 @@
1
+ import type { SeriesDefinition } from "../../../series/types";
2
+ import { FUTURES_CONTRACTS, FUTURES_SECTOR_LABELS } from "../../../market-data/futures-board";
3
+
4
+ /** Each continuous front-month contract on the futures board, as `FUT:ES`. */
5
+ export const FUTURES_SERIES: readonly SeriesDefinition[] = FUTURES_CONTRACTS.map((contract) => ({
6
+ id: `fut:${contract.code}`,
7
+ name: contract.name,
8
+ unit: "USD",
9
+ frequency: "daily",
10
+ group: "Futures",
11
+ tags: [contract.code, FUTURES_SECTOR_LABELS[contract.sector], "futures", "front month"],
12
+ expression: `FUT:${contract.code}`,
13
+ }));
@@ -4,7 +4,7 @@ import type { Quote } from "../../../types/financials";
4
4
  import { TextAttributes } from "../../../ui";
5
5
  import { formatCompact, formatNumber, formatPercentRaw } from "../../../utils/format";
6
6
  import { isBoardRowLoading, renderQuoteBoardCell, type BoardQuoteMap } from "../shared/use-quote-board";
7
- import { tickDecimals, type FuturesContract } from "./contracts";
7
+ import { tickDecimals, type FuturesContract } from "../../../market-data/futures-board";
8
8
  import { FUTURES_RETURN_COLUMNS, futuresContractName, type FuturesColumnId, type FuturesTableRow } from "./model";
9
9
  import type { FrontReturnsMap } from "./use-front-returns";
10
10
 
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from "react";
2
2
  import type { DataProvider } from "../../../types/data-provider";
3
3
  import type { PricePoint } from "../../../types/financials";
4
4
  import type { BoardQuoteMap } from "../shared/use-quote-board";
5
- import type { FuturesContract } from "./contracts";
5
+ import type { FuturesContract } from "../../../market-data/futures-board";
6
6
  import {
7
7
  frontContractCandidates,
8
8
  frontContractReturns,
@@ -1,6 +1,7 @@
1
1
  import { apiClient } from "../../../api-client";
2
2
  import type { FuturesCurvePayload } from "../../../api-client/futures-curve";
3
3
  import { createPluginCache } from "../../../data/plugin-cache";
4
+ import { isFuturesContractSpec } from "../../../market-data/futures-contract";
4
5
  import { loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
5
6
  import type { DataProvider } from "../../../types/data-provider";
6
7
  import { archivedFuturesCurve, curveLookbackDate, curveSpot, normalizeCurveRoot, unsupportedCurveRootMessage, type CurveSpot } from "./model";
@@ -13,13 +14,17 @@ const finiteOrNull = (value: unknown) => value === null || typeof value === "num
13
14
  const timestamp = (value: unknown) => typeof value === "string" && Number.isFinite(Date.parse(value));
14
15
  const date = (value: unknown) => timestamp(value) && new Date(value as string).toISOString().slice(0, 10) === value;
15
16
  const rank = (value: unknown) => value === null || typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 100;
17
+ const optionalDate = (value: unknown) => value === undefined || value === null || date(value);
18
+ /** Contract terms the pane computes with; a curve from before the server sent them has none. */
19
+ const validSpec = (spec: unknown) => spec === undefined || spec === null || isFuturesContractSpec(spec);
16
20
 
17
21
  export function validateFuturesCurve(data: FuturesCurvePayload, root: string): FuturesCurvePayload {
18
22
  if (!data || data.root !== root || !Array.isArray(data.contracts) || !Array.isArray(data.ghosts)
19
23
  || !Array.isArray(data.gaps) || !data.gaps.every((gap) => typeof gap === "string")
20
24
  || !data.catalogue || !data.slope || !timestamp(data.fetchedAt)
21
25
  || data.asOf !== null && !timestamp(data.asOf)
22
- || !["gloom", "cboe"].includes(data.source) || !["available", "partial", "unavailable"].includes(data.status)) {
26
+ || !["gloom", "cboe"].includes(data.source) || !["available", "partial", "unavailable"].includes(data.status)
27
+ || !optionalDate(data.settlementDate) || !validSpec(data.spec)) {
23
28
  throw new Error("The server returned an invalid futures curve");
24
29
  }
25
30
  const symbols = new Set<string>();
@@ -30,7 +35,9 @@ export function validateFuturesCurve(data: FuturesCurvePayload, root: string): F
30
35
  || typeof row.currency !== "string"
31
36
  || !rank(row.percentile) || !Number.isInteger(row.samples) || row.samples < 0
32
37
  || row.asOf !== null && !timestamp(row.asOf)
33
- || ![row.volume, row.openInterest, row.delayMinutes].every((value) => finiteOrNull(value) && (value === null || value >= 0))) {
38
+ || ![row.volume, row.openInterest, row.delayMinutes].every((value) => finiteOrNull(value) && (value === null || value >= 0))
39
+ || row.settlement !== undefined && !finiteOrNull(row.settlement) || !optionalDate(row.lastTrade) || !optionalDate(row.firstNotice)
40
+ || row.inDelivery !== undefined && typeof row.inDelivery !== "boolean") {
34
41
  throw new Error("The server returned an invalid futures contract");
35
42
  }
36
43
  symbols.add(row.symbol);
@@ -80,7 +87,9 @@ export async function loadFuturesCurveAsOf(root: string, date: string,
80
87
  client.getCloudFuturesCurveAsOf(normalized, curveLookbackDate(date, 30)).catch(() => null),
81
88
  ]);
82
89
  if (!curve || curve.root !== normalized || !Array.isArray(curve.contracts) || !Array.isArray(curve.gaps)
83
- || curve.contracts.some((row) => !row || typeof row.symbol !== "string" || !Number.isFinite(row.price))) {
90
+ || curve.contracts.some((row) => !row || typeof row.symbol !== "string" || !Number.isFinite(row.price)
91
+ || row.settled !== undefined && typeof row.settled !== "boolean" || !optionalDate(row.firstNotice) || !optionalDate(row.lastTrade))
92
+ || !validSpec(curve.spec)) {
84
93
  throw new Error("The server returned an invalid past futures curve");
85
94
  }
86
95
  return archivedFuturesCurve(normalized, curve, { "1W": week, "1M": month }, new Date().toISOString());
@@ -1,7 +1,9 @@
1
- import type { HeadlessPaneDefinition, HeadlessPaneFreshness } from "../../../types/plugin";
1
+ import type { FuturesContract, FuturesCurvePayload } from "../../../api-client/futures-curve";
2
+ import { futuresSpecLines } from "../../../market-data/futures-contract";
3
+ import type { HeadlessPaneColumn, HeadlessPaneDefinition, HeadlessPaneEntry, HeadlessPaneFreshness } from "../../../types/plugin";
2
4
  import { newestReportTime, oldestReportTime } from "../../../utils/utc-time";
3
5
  import { fetchFuturesCurve, loadCurveSpot, loadFuturesCurveAsOf } from "./client";
4
- import { basisSpotSymbol, contractBasis, curveAsOfDate, curveSpotLabel, normalizeCurveRoot, thinContractCount, unsupportedCurveRootMessage } from "./model";
6
+ import { basisSpotSymbol, catalogueCurveUnit, contractBasis, curveAsOfDate, curveBasisPercent, curveChangeText, curveContractCode, curvePrice, curveRoundedPrice, curveSpotLabel, curveSpreadLabel, curveTimestamp, curveUnitLabel, normalizeCurveRoot, thinContractCount, unsupportedCurveRootMessage, type ContractBasis } from "./model";
5
7
 
6
8
  /** The root a report shows when none is given. */
7
9
  const DEFAULT_ROOT = "ES";
@@ -12,6 +14,63 @@ const rank = (value: number | null) => value == null ? null : Math.round(value);
12
14
  /** The basis fields are read to four decimals, finer than any cell shows. */
13
15
  const basisValue = (value: number | null) => value == null ? null : Number(value.toFixed(4));
14
16
 
17
+ /**
18
+ * One contract as the report reads it, the same fields in the same order for
19
+ * every root. Prices and changes are at the root's tick precision. `price` is
20
+ * the latest trade and `settlement` the exchange settlement for the curve's
21
+ * settlement session (a past curve's settled rows have no separate trade).
22
+ */
23
+ function contractRow(row: FuturesContract, data: FuturesCurvePayload, root: string, past: boolean, basis?: ContractBasis) {
24
+ const price = (value: number | null | undefined) => curveRoundedPrice(value, root);
25
+ return {
26
+ symbol: row.symbol, label: row.label, expiration: row.expiration, lastTrade: row.lastTrade ?? row.expiration,
27
+ firstNotice: row.firstNotice ?? null, inDelivery: row.inDelivery ?? false,
28
+ settlement: price(row.settlement), settlementDate: row.settlement != null ? data.settlementDate ?? null : null,
29
+ price: past && row.settlement != null ? null : price(row.price), change: price(row.change),
30
+ asOf: row.asOf, stale: row.stale, volume: row.volume, openInterest: row.openInterest, percentile: rank(row.percentile),
31
+ samples: row.samples, historyStart: row.historyStart, historyEnd: row.historyEnd,
32
+ currency: row.currency, quoteUnit: curveUnitLabel(data) ?? row.quoteUnit, delayMinutes: row.delayMinutes,
33
+ ...(basis ? { vsSpotPct: basisValue(basis.vsSpotPct), annualisedBasisPct: basisValue(basis.annualisedBasisPct) } : {}),
34
+ };
35
+ }
36
+
37
+ /** The text table: what a hedge reads, in one order for every root; JSON keeps every field. */
38
+ function contractColumns(root: string, settlementDate: string | null, options: { basis: boolean; last: boolean; notice: boolean }): HeadlessPaneColumn[] {
39
+ const price = (value: unknown) => typeof value === "number" ? curvePrice(value, root) : "--";
40
+ const date = (value: unknown) => typeof value === "string" ? value : "--";
41
+ return [
42
+ { key: "symbol", header: "Contract", shrink: false, format: (value) => curveContractCode(String(value)) },
43
+ { key: "lastTrade", header: "Last Trade", shrink: false, format: date },
44
+ // Cash-settled roots have no first notice day.
45
+ ...options.notice ? [{ key: "firstNotice", header: "1st Notice", shrink: false,
46
+ format: (value: unknown, row: Record<string, unknown>) => typeof value === "string" ? `${value}${row.inDelivery ? " passed" : ""}` : "--" }] : [],
47
+ { key: "settlement", header: settlementDate ? `Settle ${settlementDate}` : "Settle", align: "right", format: price },
48
+ // A Cboe price is the settlement itself, with no separate last trade.
49
+ ...options.last ? [{ key: "price", header: "Last", align: "right" as const, format: price }] : [],
50
+ { key: "change", header: "Change", align: "right", format: (value) => typeof value === "number" ? curveChangeText(value, root) : "--" },
51
+ ...options.basis ? [{ key: "vsSpotPct", header: "Vs Spot", align: "right" as const, format: (value: unknown) => curveBasisPercent(typeof value === "number" ? value : null, 2) },
52
+ { key: "annualisedBasisPct", header: "Ann Basis", align: "right" as const, format: (value: unknown) => curveBasisPercent(typeof value === "number" ? value : null, 1) }] : [],
53
+ { key: "asOf", header: "As Of UTC", shrink: false, format: (value) => typeof value === "string" ? curveTimestamp(value) : "--" },
54
+ { key: "openInterest", header: "Open Int", align: "right", format: (value) => typeof value === "number" ? value.toLocaleString("en-US") : "--" },
55
+ { key: "volume", header: "Volume", align: "right", format: (value) => typeof value === "number" ? value.toLocaleString("en-US") : "--" },
56
+ { key: "percentile", header: "Pctl", align: "right", format: (value) => typeof value === "number" ? String(value) : "--" },
57
+ ];
58
+ }
59
+
60
+ /** What one contract is: the terms a hedge is sized on, once rather than on every row, worded as `ticker` words them. */
61
+ function specEntries(data: FuturesCurvePayload): HeadlessPaneEntry[] {
62
+ const spec = data.spec;
63
+ // A root without terms still says what its prices count: Dutch TTF gas is euros per MWh.
64
+ if (!spec) {
65
+ const unit = catalogueCurveUnit(data.root);
66
+ return unit ? [{ key: "unit", label: "Unit", value: unit }] : [];
67
+ }
68
+ return futuresSpecLines(spec).map((line) => {
69
+ const value = spec[line.key as keyof typeof spec];
70
+ return { key: line.key, label: line.label, value, ...line.value === String(value) ? {} : { formatted: line.value } };
71
+ });
72
+ }
73
+
15
74
  export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
16
75
  discovery: { aliases: ["CTM"], dataRequirements: ["Gloom Cloud futures curve endpoint"],
17
76
  limitations: ["Listed-contract catalogues can be incomplete", "Ghosts and percentiles use the same listed contracts", "Cboe VIX is daily settlement"] },
@@ -35,6 +94,8 @@ export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
35
94
  spotSymbol ? loadCurveSpot(spotSymbol, ctx.marketData, now) : null,
36
95
  ]);
37
96
  const bases = spot ? data.contracts.map((row) => contractBasis(row, spot)) : [];
97
+ const unit = curveUnitLabel(data);
98
+ const terms = specEntries(data);
38
99
  const notices = [...args.argument ? [] : [`Showing ${DEFAULT_ROOT}. Try fn CTM ${EXAMPLE_ROOT}.`],
39
100
  ...spot ? [spot.status === "ok" ? `Basis against ${curveSpotLabel(spot, root, now)}.` : `Basis blank: ${spot.reason}.`] : []];
40
101
  // Dated by the contracts' own quotes; the same-contract history rows are a year of context, not observations.
@@ -46,17 +107,17 @@ export const futuresCurveHeadless: HeadlessPaneDefinition<"bundle"> = {
46
107
  return {
47
108
  freshness,
48
109
  sections: [
49
- { title: "Contracts", rows: data.contracts.map((row, index) => {
50
- const basis = bases[index];
51
- return { ...row, percentile: rank(row.percentile),
52
- ...(basis ? { vsSpotPct: basisValue(basis.vsSpotPct), annualisedBasisPct: basisValue(basis.annualisedBasisPct) } : {}) };
53
- }) },
54
- { title: "Front spread", rows: [{ ...data.slope, annualizedRollYield: data.slope.annualizedRollYield == null ? null : Number(data.slope.annualizedRollYield.toFixed(2)),
110
+ { title: "Contracts", columns: contractColumns(root, data.settlementDate ?? null,
111
+ { basis: !!spot, last: data.source !== "cboe", notice: data.contracts.some((row) => row.firstNotice) }),
112
+ rows: data.contracts.map((row, index) => contractRow(row, data, root, !!date, bases[index])) },
113
+ { title: "Front spread", rows: [{ label: curveSpreadLabel(data.slope), ...data.slope, value: curveRoundedPrice(data.slope.value, root),
114
+ annualizedRollYield: data.slope.annualizedRollYield == null ? null : Number(data.slope.annualizedRollYield.toFixed(2)),
55
115
  percentile: rank(data.slope.percentile), rollPercentile: rank(data.slope.rollPercentile) }] },
116
+ ...terms.length ? [{ title: "Contract terms", entries: terms }] : [],
56
117
  ...data.ghosts.map((ghost) => ({ title: `${ghost.label} same-contract history`, rows: ghost.points.map((point) => ({ ...point })) })),
57
118
  ],
58
119
  errors: data.gaps,
59
- metadata: { ...data, ...(spot ? { spot, basisBlankedThin: thinContractCount(bases) } : {}), ...(args.argument ? {} : { defaultArgument: DEFAULT_ROOT }),
120
+ metadata: { ...data, quoteUnit: unit, ...(spot ? { spot, basisBlankedThin: thinContractCount(bases) } : {}), ...(args.argument ? {} : { defaultArgument: DEFAULT_ROOT }),
60
121
  ...(notices.length ? { notices } : {}),
61
122
  complete: data.status === "available", percentileBasis: "Same-contract observations within one year; actual sample start/end retained" },
62
123
  };
@@ -18,7 +18,7 @@ export const futuresCurveModule: PluginModule = {
18
18
  }],
19
19
  paneTemplates: [{ id: "futures-curve-pane", paneId: "futures-curve", label: "Futures Curve",
20
20
  description: "Listed futures contracts, historical curves, roll yield and open interest including VIX and CME crypto futures.",
21
- keywords: ["ctm", "futures", "curve", "contango", "backwardation", "roll", "vix"],
21
+ keywords: ["ctm", "futures", "curve", "contango", "backwardation", "roll", "vix", "crude oil", "natural gas"],
22
22
  shortcut: { prefix: "CTM", aliases: ["CT"], argKind: "text", argPlaceholder: "root", argOptional: true,
23
23
  argOptions: () => CURVE_ROOTS },
24
24
  headless: futuresCurveHeadless,