gloomberb 0.16.2 → 0.16.4

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 (527) hide show
  1. package/package.json +4 -1
  2. package/src/api-client/askg.ts +43 -0
  3. package/src/api-client/auth.ts +15 -0
  4. package/src/api-client/beneficial-owners.ts +4 -0
  5. package/src/api-client/chat.ts +19 -0
  6. package/src/api-client/company-kpis.ts +14 -2
  7. package/src/api-client/data.ts +34 -16
  8. package/src/api-client/index.ts +12 -0
  9. package/src/api-client/normalizers.ts +27 -0
  10. package/src/api-client/paths.ts +88 -23
  11. package/src/api-client/request.ts +2 -1
  12. package/src/api-client/research-activity.ts +31 -0
  13. package/src/api-client/socket.ts +39 -8
  14. package/src/api-client/types.ts +57 -1
  15. package/src/api-client/upgrade-experiment.ts +90 -0
  16. package/src/app/global-shortcuts.ts +11 -1
  17. package/src/app/keybindings/actions.ts +10 -0
  18. package/src/app/pane-runtime/index.tsx +8 -0
  19. package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
  20. package/src/app/pane-runtime/plugin-bindings.ts +65 -25
  21. package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
  22. package/src/app/pane-runtime/ticker-open-runtime.ts +18 -1
  23. package/src/app/runtime/desktop-deeplink.ts +5 -0
  24. package/src/app/star-prompt/model.ts +98 -0
  25. package/src/app/star-prompt/runtime.ts +41 -0
  26. package/src/app/star-prompt/status-line.tsx +190 -0
  27. package/src/app.tsx +13 -7
  28. package/src/architecture/core-builtin-allowlist.json +70 -0
  29. package/src/brokers/account-cache.ts +45 -0
  30. package/src/brokers/signed-in/adapter.ts +33 -2
  31. package/src/brokers/signed-in/client.ts +10 -0
  32. package/src/brokers/signed-in/sign-in-dialog.tsx +23 -9
  33. package/src/brokers/signed-in/sign-in.ts +62 -5
  34. package/src/capabilities/registry.ts +8 -1
  35. package/src/capabilities/types.ts +2 -0
  36. package/src/cli/command-options.ts +74 -0
  37. package/src/cli/commands/command-utils.ts +29 -0
  38. package/src/cli/commands/crypto-hints.ts +12 -4
  39. package/src/cli/commands/market.ts +524 -148
  40. package/src/cli/commands/options-chain.ts +172 -0
  41. package/src/cli/commands/options-leaps.ts +422 -0
  42. package/src/cli/commands/overview.ts +223 -42
  43. package/src/cli/commands/search.ts +29 -8
  44. package/src/cli/commands/system.ts +99 -19
  45. package/src/cli/commands/themes.ts +64 -0
  46. package/src/cli/commands/ticker.ts +200 -73
  47. package/src/cli/desktop-pane-shot.ts +100 -16
  48. package/src/cli/errors.ts +25 -2
  49. package/src/cli/freshness.ts +7 -4
  50. package/src/cli/fx-pair.ts +57 -0
  51. package/src/cli/help.ts +40 -7
  52. package/src/cli/history-rows.ts +187 -15
  53. package/src/cli/index-roots.ts +51 -0
  54. package/src/cli/index.ts +21 -13
  55. package/src/cli/listing-arg.ts +211 -3
  56. package/src/cli/not-a-ticker.ts +37 -0
  57. package/src/cli/options.ts +55 -7
  58. package/src/cli/pane-functions/capabilities.ts +13 -2
  59. package/src/cli/pane-functions/catalog.ts +13 -2
  60. package/src/cli/pane-functions/data.ts +36 -5
  61. package/src/cli/pane-functions/dom.ts +89 -28
  62. package/src/cli/pane-functions/freshness.ts +205 -26
  63. package/src/cli/pane-functions/function-help.ts +71 -24
  64. package/src/cli/pane-functions/headless.ts +168 -35
  65. package/src/cli/pane-functions/index.ts +12 -2
  66. package/src/cli/pane-functions/market-session.ts +133 -0
  67. package/src/cli/pane-functions/options.ts +15 -4
  68. package/src/cli/pane-functions/report-notices.ts +63 -0
  69. package/src/cli/pane-functions/report.ts +12 -1
  70. package/src/cli/pane-functions/resolver.ts +32 -8
  71. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  72. package/src/cli/pane-functions/screenshot.ts +109 -23
  73. package/src/cli/registry.ts +8 -4
  74. package/src/cli/report-tables.ts +460 -0
  75. package/src/cli/result.ts +63 -16
  76. package/src/cli/row-window.ts +76 -0
  77. package/src/cli/scroll-truncation.ts +34 -0
  78. package/src/components/chart/composite/composite-chart.tsx +43 -4
  79. package/src/components/chart/composite/legend.tsx +39 -6
  80. package/src/components/chart/composite/rasterizer.ts +64 -4
  81. package/src/components/chart/composite/series-cues.ts +71 -0
  82. package/src/components/chart/composite/text-renderer.ts +16 -8
  83. package/src/components/chart/composite/types.ts +3 -0
  84. package/src/components/command-bar/commands/direct/index.ts +9 -1
  85. package/src/components/command-bar/commands/plugin/items.ts +3 -1
  86. package/src/components/command-bar/commands/registry.ts +7 -0
  87. package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
  88. package/src/components/command-bar/pane-templates/workflow.ts +5 -0
  89. package/src/components/command-bar/routes/root/command-items.ts +2 -0
  90. package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
  91. package/src/components/command-bar/routes/root/results.ts +40 -10
  92. package/src/components/command-bar/routes/root/runtime.ts +8 -0
  93. package/src/components/command-bar/routes/root/search-providers.ts +97 -14
  94. package/src/components/command-bar/surface/index.tsx +18 -4
  95. package/src/components/command-bar/theme-picker.tsx +48 -13
  96. package/src/components/command-bar/workflow/ops.ts +5 -3
  97. package/src/components/data-table/export.ts +6 -51
  98. package/src/components/data-table/view.tsx +31 -10
  99. package/src/components/layout/floating-pane.tsx +6 -2
  100. package/src/components/layout/market-summary.ts +23 -9
  101. package/src/components/layout/pane/content.tsx +46 -29
  102. package/src/components/layout/pane/cycle-order.ts +2 -11
  103. package/src/components/layout/pane/header.tsx +2 -1
  104. package/src/components/layout/pane/title.ts +1 -1
  105. package/src/components/layout/presentation.ts +22 -0
  106. package/src/components/layout/shell/active-drag.ts +67 -35
  107. package/src/components/layout/shell/cursor-occlusion.ts +6 -5
  108. package/src/components/layout/shell/drag/index.ts +16 -7
  109. package/src/components/layout/shell/drag/live.ts +193 -0
  110. package/src/components/layout/shell/drag/overlays.tsx +179 -35
  111. package/src/components/layout/shell/drag/runtime.ts +62 -50
  112. package/src/components/layout/shell/drag/slide.ts +10 -0
  113. package/src/components/layout/shell/index.tsx +84 -57
  114. package/src/components/layout/shell/layout-state.ts +5 -11
  115. package/src/components/layout/shell/menu.ts +28 -1
  116. package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
  117. package/src/components/layout/shell/native/surfaces.ts +30 -14
  118. package/src/components/layout/shell/pane/actions.ts +2 -1
  119. package/src/components/layout/shell/pane/layers.tsx +461 -180
  120. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  121. package/src/components/layout/shell/pane/new-layout.ts +116 -0
  122. package/src/components/layout/shell/shortcuts.ts +5 -2
  123. package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
  124. package/src/components/layout/shell/visible-layout.ts +44 -1
  125. package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
  126. package/src/components/layout/status-bar.tsx +4 -1
  127. package/src/components/markdown-text.tsx +9 -5
  128. package/src/components/metric-treemap/heat-surface.tsx +27 -8
  129. package/src/components/metric-treemap/heat-tiles.ts +48 -17
  130. package/src/components/onboarding/onboarding-frame.tsx +33 -10
  131. package/src/components/onboarding/onboarding-wizard.tsx +49 -40
  132. package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
  133. package/src/components/onboarding/pro-step-layout.ts +86 -0
  134. package/src/components/onboarding/use-onboarding-upgrade.ts +6 -2
  135. package/src/components/ui/button.tsx +10 -0
  136. package/src/components/ui/data-table/index.tsx +38 -0
  137. package/src/components/ui/data-table/types.ts +8 -1
  138. package/src/components/ui/data-table/visible-range.ts +2 -0
  139. package/src/components/ui/icon.tsx +11 -2
  140. package/src/components/ui/index.ts +1 -1
  141. package/src/core/connection-health.ts +1 -1
  142. package/src/core/state/app/layout-reducer.ts +89 -3
  143. package/src/core/state/app/state.ts +8 -5
  144. package/src/core/state/app/types.ts +13 -2
  145. package/src/data/config/layout.ts +55 -21
  146. package/src/data/config/store/fold-panes.ts +149 -0
  147. package/src/data/config/store/migrations.ts +7 -0
  148. package/src/data/config/store/node.ts +27 -6
  149. package/src/data/config/store/normalize.ts +37 -3
  150. package/src/data/json-persistence.ts +17 -3
  151. package/src/data/json-storage.ts +2 -0
  152. package/src/data/memory-resource-store.ts +46 -0
  153. package/src/i18n/es.ts +14 -1
  154. package/src/i18n/ja.ts +14 -1
  155. package/src/i18n/ko.ts +14 -1
  156. package/src/i18n/zh-cn.ts +14 -1
  157. package/src/i18n/zh-tw.ts +14 -1
  158. package/src/layout/desks.ts +1 -2
  159. package/src/layout/pane-layout-move.ts +264 -0
  160. package/src/layout/pane-manager/hidden-panes.ts +160 -0
  161. package/src/layout/pane-manager/index.ts +1 -0
  162. package/src/market-data/coordinator/entries.ts +7 -1
  163. package/src/market-data/coordinator/quotes.ts +2 -2
  164. package/src/market-data/market/freshness.ts +156 -11
  165. package/src/market-data/market/status.ts +40 -0
  166. package/src/market-data/options-alternatives.ts +69 -0
  167. package/src/market-data/quotes/contributions.ts +19 -2
  168. package/src/market-data/quotes/freshness.ts +5 -0
  169. package/src/market-data/quotes/metadata.ts +16 -0
  170. package/src/market-data/quotes/screener-live-quotes.ts +56 -5
  171. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  172. package/src/plugins/builtin/account-management/model.ts +1 -0
  173. package/src/plugins/builtin/account-management/navigation.ts +1 -1
  174. package/src/plugins/builtin/account-management/pane.tsx +31 -4
  175. package/src/plugins/builtin/alerts/quotes.ts +3 -0
  176. package/src/plugins/builtin/analytics/pane-model.ts +10 -6
  177. package/src/plugins/builtin/analytics/risk-headless.ts +3 -1
  178. package/src/plugins/builtin/analytics/risk-model.ts +37 -8
  179. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -4
  180. package/src/plugins/builtin/attention/pane.tsx +1 -1
  181. package/src/plugins/builtin/backtest/pane.tsx +1 -1
  182. package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
  183. package/src/plugins/builtin/broker-manager/index.tsx +7 -3
  184. package/src/plugins/builtin/broker-manager/model.ts +8 -0
  185. package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
  186. package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
  187. package/src/plugins/builtin/broker-manager/table.ts +5 -0
  188. package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
  189. package/src/plugins/builtin/catalysts/detail.tsx +1 -1
  190. package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
  191. package/src/plugins/builtin/chat/channels.ts +34 -36
  192. package/src/plugins/builtin/chat/command-bar.ts +138 -0
  193. package/src/plugins/builtin/chat/composer-commands.ts +21 -1
  194. package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
  195. package/src/plugins/builtin/chat/content/footer.tsx +5 -3
  196. package/src/plugins/builtin/chat/content/index.tsx +21 -1
  197. package/src/plugins/builtin/chat/content/mentions.ts +2 -1
  198. package/src/plugins/builtin/chat/content/user-map.ts +3 -1
  199. package/src/plugins/builtin/chat/controller/index.ts +48 -0
  200. package/src/plugins/builtin/chat/conversations.ts +256 -0
  201. package/src/plugins/builtin/chat/discord-command.ts +91 -0
  202. package/src/plugins/builtin/chat/edit-window.ts +12 -6
  203. package/src/plugins/builtin/chat/ghost-user.ts +14 -0
  204. package/src/plugins/builtin/chat/index.tsx +40 -2
  205. package/src/plugins/builtin/chat/layout.ts +2 -0
  206. package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
  207. package/src/plugins/builtin/chat/message/header.tsx +24 -15
  208. package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
  209. package/src/plugins/builtin/chat/message/render-state.ts +3 -0
  210. package/src/plugins/builtin/chat/pane-requests.ts +60 -0
  211. package/src/plugins/builtin/chat/pane-state.ts +32 -2
  212. package/src/plugins/builtin/chat/pane.tsx +8 -0
  213. package/src/plugins/builtin/cloud/askg/controller.ts +112 -4
  214. package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
  215. package/src/plugins/builtin/cloud/askg/manifest.ts +1 -0
  216. package/src/plugins/builtin/cloud/askg/model.ts +129 -70
  217. package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
  218. package/src/plugins/builtin/cloud/askg/protocol.ts +40 -2
  219. package/src/plugins/builtin/cloud/askg/tool-display.ts +437 -0
  220. package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
  221. package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
  222. package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
  223. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +360 -0
  224. package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
  225. package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
  226. package/src/plugins/builtin/cloud/plugin.tsx +36 -1
  227. package/src/plugins/builtin/cloud/starter-symbols.ts +8 -0
  228. package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
  229. package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
  230. package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
  231. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +666 -0
  232. package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
  233. package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
  234. package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
  235. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +234 -0
  236. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +153 -0
  237. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +168 -0
  238. package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
  239. package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
  240. package/src/plugins/builtin/cloud/upgrade-dialog.tsx +26 -2
  241. package/src/plugins/builtin/cloud/upgrade-personalization.ts +57 -0
  242. package/src/plugins/builtin/cloud/upgrade-tickers.ts +124 -0
  243. package/src/plugins/builtin/comment-letters/client.ts +1 -3
  244. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  245. package/src/plugins/builtin/company-kpis/client.ts +23 -8
  246. package/src/plugins/builtin/company-kpis/headless.ts +3 -1
  247. package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
  248. package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
  249. package/src/plugins/builtin/composite-plugins.ts +107 -64
  250. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
  251. package/src/plugins/builtin/credit-boards/index.tsx +21 -21
  252. package/src/plugins/builtin/credit-boards/model.ts +0 -1
  253. package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
  254. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
  255. package/src/plugins/builtin/debt-maturities/client.ts +37 -9
  256. package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
  257. package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
  258. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  259. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  260. package/src/plugins/builtin/earnings-calls/data.ts +28 -7
  261. package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
  262. package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
  263. package/src/plugins/builtin/econ/calendar-model.ts +42 -17
  264. package/src/plugins/builtin/econ/detail-view.tsx +2 -2
  265. package/src/plugins/builtin/econ/index.tsx +68 -22
  266. package/src/plugins/builtin/econ-statistics/headless.ts +12 -2
  267. package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
  268. package/src/plugins/builtin/econ-statistics/view.ts +17 -0
  269. package/src/plugins/builtin/executives/data.ts +17 -6
  270. package/src/plugins/builtin/executives/pane.tsx +16 -7
  271. package/src/plugins/builtin/filing-events/pane.tsx +22 -5
  272. package/src/plugins/builtin/fx-matrix/freshness.ts +65 -0
  273. package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
  274. package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
  275. package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
  276. package/src/plugins/builtin/gpu/headless.ts +9 -3
  277. package/src/plugins/builtin/gpu/model.ts +14 -5
  278. package/src/plugins/builtin/help/index.tsx +1 -0
  279. package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
  280. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  281. package/src/plugins/builtin/holders/client.ts +3 -6
  282. package/src/plugins/builtin/holders/format.ts +31 -1
  283. package/src/plugins/builtin/holders/headless.ts +32 -6
  284. package/src/plugins/builtin/holders/pane.tsx +25 -13
  285. package/src/plugins/builtin/holders/report-header.ts +46 -5
  286. package/src/plugins/builtin/insider/index.tsx +4 -4
  287. package/src/plugins/builtin/iv-history/charts.tsx +21 -7
  288. package/src/plugins/builtin/iv-history/client.ts +12 -2
  289. package/src/plugins/builtin/iv-history/format.ts +33 -2
  290. package/src/plugins/builtin/iv-history/headless.ts +22 -10
  291. package/src/plugins/builtin/iv-history/index.tsx +3 -3
  292. package/src/plugins/builtin/iv-history/model.ts +61 -13
  293. package/src/plugins/builtin/iv-history/pane.tsx +11 -3
  294. package/src/plugins/builtin/iv-history/screen-pane.tsx +42 -18
  295. package/src/plugins/builtin/jobs/pane.tsx +1 -1
  296. package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
  297. package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
  298. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  299. package/src/plugins/builtin/kelly-sizer/pane.tsx +121 -45
  300. package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
  301. package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
  302. package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
  303. package/src/plugins/builtin/layout-manager/index.tsx +9 -1
  304. package/src/plugins/builtin/macro-day/client.ts +24 -0
  305. package/src/plugins/builtin/macro-day/headless.ts +11 -8
  306. package/src/plugins/builtin/macro-day/index.tsx +3 -0
  307. package/src/plugins/builtin/macro-day/model.ts +11 -6
  308. package/src/plugins/builtin/macro-day/pane.tsx +12 -8
  309. package/src/plugins/builtin/macro-day/release-table.ts +40 -0
  310. package/src/plugins/builtin/macro-day/releases.ts +62 -44
  311. package/src/plugins/builtin/market-heatmap/data.ts +25 -5
  312. package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
  313. package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
  314. package/src/plugins/builtin/market-heatmap/model.ts +94 -3
  315. package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
  316. package/src/plugins/builtin/market-movers/headless.ts +31 -4
  317. package/src/plugins/builtin/market-movers/index.tsx +8 -1
  318. package/src/plugins/builtin/market-movers/model.ts +71 -17
  319. package/src/plugins/builtin/market-movers/table.ts +50 -23
  320. package/src/plugins/builtin/members/pane.tsx +10 -0
  321. package/src/plugins/builtin/news/headless.ts +9 -2
  322. package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
  323. package/src/plugins/builtin/openfda/client.ts +1 -1
  324. package/src/plugins/builtin/options/carry.ts +95 -0
  325. package/src/plugins/builtin/options/index.tsx +58 -5
  326. package/src/plugins/builtin/options/strike-window.ts +183 -0
  327. package/src/plugins/builtin/options/table.ts +55 -3
  328. package/src/plugins/builtin/options/types.ts +8 -1
  329. package/src/plugins/builtin/options/view.tsx +161 -12
  330. package/src/plugins/builtin/options-positioning/headless.ts +4 -2
  331. package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
  332. package/src/plugins/builtin/options-scenario/client.ts +73 -17
  333. package/src/plugins/builtin/options-scenario/headless.ts +71 -24
  334. package/src/plugins/builtin/options-scenario/hedge.ts +284 -0
  335. package/src/plugins/builtin/options-scenario/index.tsx +9 -2
  336. package/src/plugins/builtin/options-scenario/model.ts +33 -0
  337. package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
  338. package/src/plugins/builtin/pe-band/model.ts +2 -2
  339. package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
  340. package/src/plugins/builtin/perps/equity-row.tsx +8 -5
  341. package/src/plugins/builtin/perps/model.ts +16 -5
  342. package/src/plugins/builtin/perps/pane.tsx +1 -1
  343. package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
  344. package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
  345. package/src/plugins/builtin/plugin-marketplace/pane.tsx +344 -32
  346. package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
  347. package/src/plugins/builtin/plugin-module.ts +87 -4
  348. package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
  349. package/src/plugins/builtin/portfolio-list/allocation.ts +3 -0
  350. package/src/plugins/builtin/portfolio-list/cached-account.ts +18 -9
  351. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +71 -36
  352. package/src/plugins/builtin/portfolio-list/cli/render.ts +89 -18
  353. package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
  354. package/src/plugins/builtin/portfolio-list/headless.ts +40 -7
  355. package/src/plugins/builtin/portfolio-list/pane/index.tsx +7 -4
  356. package/src/plugins/builtin/portfolio-list/summary/index.tsx +22 -4
  357. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
  358. package/src/plugins/builtin/realized-vol/headless.ts +3 -0
  359. package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
  360. package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -2
  361. package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
  362. package/src/plugins/builtin/research/relative-valuation-model.ts +7 -3
  363. package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
  364. package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
  365. package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
  366. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
  367. package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
  368. package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
  369. package/src/plugins/builtin/risk-factors/data.ts +23 -9
  370. package/src/plugins/builtin/risk-factors/headless.ts +5 -2
  371. package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
  372. package/src/plugins/builtin/seasonality/pane.tsx +1 -1
  373. package/src/plugins/builtin/sec/index.tsx +5 -5
  374. package/src/plugins/builtin/sectors/client.ts +10 -2
  375. package/src/plugins/builtin/sectors/headless.ts +35 -6
  376. package/src/plugins/builtin/sectors/index.tsx +18 -1
  377. package/src/plugins/builtin/sectors/sector-model.ts +150 -41
  378. package/src/plugins/builtin/shared/command-tab.ts +51 -0
  379. package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
  380. package/src/plugins/builtin/shared/members-menu.tsx +260 -0
  381. package/src/plugins/builtin/shared/report-freshness.ts +50 -2
  382. package/src/plugins/builtin/shared/ticker-request.ts +25 -1
  383. package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
  384. package/src/plugins/builtin/shared/volatility/options.ts +1 -46
  385. package/src/plugins/builtin/short-interest/index.tsx +19 -4
  386. package/src/plugins/builtin/short-interest/surface.tsx +4 -4
  387. package/src/plugins/builtin/short-volume/index.tsx +1 -10
  388. package/src/plugins/builtin/short-volume/pane.tsx +1 -1
  389. package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
  390. package/src/plugins/builtin/supply-chain/model.ts +1 -1
  391. package/src/plugins/builtin/themes/pane.tsx +3 -0
  392. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
  393. package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
  394. package/src/plugins/builtin/ticker-detail/headless.ts +63 -25
  395. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -4
  396. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +3 -2
  397. package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
  398. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
  399. package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
  400. package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
  401. package/src/plugins/builtin/treasury-auctions/headless.ts +40 -4
  402. package/src/plugins/builtin/treasury-auctions/index.tsx +11 -9
  403. package/src/plugins/builtin/treasury-auctions/model.ts +197 -30
  404. package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
  405. package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
  406. package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
  407. package/src/plugins/builtin/vol-surface/client.ts +6 -2
  408. package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
  409. package/src/plugins/builtin/vol-surface/headless.ts +124 -20
  410. package/src/plugins/builtin/vol-surface/model.ts +23 -11
  411. package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
  412. package/src/plugins/builtin/vol-surface/tables.ts +124 -0
  413. package/src/plugins/builtin/world-indices/client.ts +22 -4
  414. package/src/plugins/builtin/world-indices/headless.ts +54 -27
  415. package/src/plugins/builtin/world-indices/model.ts +4 -2
  416. package/src/plugins/builtin/world-indices/table.tsx +13 -2
  417. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +2 -0
  418. package/src/plugins/builtin/world-venue-map/basemap.ts +18 -0
  419. package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
  420. package/src/plugins/builtin/world-venue-map/geo-series.ts +1 -1
  421. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +2 -1
  422. package/src/plugins/builtin/world-venue-map/index.ts +6 -6
  423. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +27 -14
  424. package/src/plugins/builtin/world-venue-map/layers.ts +68 -10
  425. package/src/plugins/builtin/world-venue-map/map.tsx +198 -62
  426. package/src/plugins/builtin/world-venue-map/model.ts +16 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +3 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
  429. package/src/plugins/builtin/world-venue-map/pane.tsx +16 -10
  430. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  431. package/src/plugins/builtin-editorial.ts +126 -0
  432. package/src/plugins/catalog-backend.ts +16 -9
  433. package/src/plugins/catalog-browser.ts +127 -63
  434. package/src/plugins/catalog-manifest.ts +73 -40
  435. package/src/plugins/catalog-ui.ts +26 -6
  436. package/src/plugins/extracted-plugins.ts +7 -1
  437. package/src/plugins/ownership.ts +150 -7
  438. package/src/plugins/plugin-functions.ts +54 -0
  439. package/src/plugins/plugin-off.ts +36 -0
  440. package/src/plugins/registry/host-actions.ts +16 -0
  441. package/src/plugins/registry/index.ts +84 -24
  442. package/src/plugins/registry/plugin-state.ts +25 -1
  443. package/src/plugins/runtime/context.tsx +29 -0
  444. package/src/react/input.ts +48 -1
  445. package/src/remote/app-host.tsx +5 -0
  446. package/src/remote/controller.ts +3 -53
  447. package/src/remote/matching.ts +69 -0
  448. package/src/remote/schema.ts +1 -1
  449. package/src/remote/semantic-tree.tsx +14 -0
  450. package/src/remote/types.ts +2 -0
  451. package/src/renderers/browser/app-services.ts +3 -1
  452. package/src/renderers/dom/data-table/dom.ts +31 -0
  453. package/src/renderers/dom/data-table/index.tsx +5 -0
  454. package/src/renderers/dom/desktop/icons.tsx +14 -0
  455. package/src/renderers/dom/desktop/query-bar.tsx +59 -32
  456. package/src/renderers/dom/host/box.tsx +113 -17
  457. package/src/renderers/dom/host/drag-shield.ts +35 -0
  458. package/src/renderers/dom/host/live-frame.ts +62 -0
  459. package/src/renderers/dom/host/mouse.ts +8 -1
  460. package/src/renderers/dom/host/scroll-box.tsx +6 -5
  461. package/src/renderers/dom/host/tabs.tsx +3 -2
  462. package/src/renderers/dom/input-host.tsx +6 -1
  463. package/src/renderers/dom/styles.css +26 -5
  464. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
  465. package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
  466. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
  467. package/src/renderers/electrobun/bun/desktop/initialization.ts +15 -1
  468. package/src/renderers/electrobun/shared/protocol.ts +12 -1
  469. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -1
  470. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
  471. package/src/renderers/electrobun/view/host/native.ts +0 -10
  472. package/src/renderers/electrobun/view/host/window-move.ts +28 -0
  473. package/src/renderers/electrobun/view/main.tsx +4 -1
  474. package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
  475. package/src/renderers/electrobun/view/ui-host.tsx +2 -5
  476. package/src/renderers/opentui/input-host.tsx +6 -1
  477. package/src/renderers/opentui/start.tsx +9 -0
  478. package/src/renderers/opentui/ui-host.tsx +7 -1
  479. package/src/shares/portable-layout.ts +16 -6
  480. package/src/sources/gloomberb-cloud/index.ts +19 -10
  481. package/src/sources/gloomberb-cloud/normalizers.ts +20 -21
  482. package/src/sources/listing-symbols.ts +11 -5
  483. package/src/sources/provider-errors.ts +88 -3
  484. package/src/sources/provider-router/batches.ts +3 -3
  485. package/src/sources/provider-router/cached-routes.ts +8 -4
  486. package/src/sources/provider-router/financial-routes.ts +13 -7
  487. package/src/sources/provider-router/financials.ts +106 -16
  488. package/src/sources/provider-router/history.ts +27 -11
  489. package/src/sources/provider-router/index.ts +1 -1
  490. package/src/sources/provider-router/primary.ts +24 -6
  491. package/src/sources/sec-edgar.ts +68 -8
  492. package/src/state/pane-scroll-registry.tsx +67 -35
  493. package/src/sync/core-contributors.ts +4 -3
  494. package/src/test-support/cli-context.ts +2 -1
  495. package/src/test-support/data-provider.ts +34 -0
  496. package/src/test-support/margin-account.ts +108 -0
  497. package/src/test-support/shell-pane-keys.tsx +1 -0
  498. package/src/theme/series-colors.ts +46 -0
  499. package/src/theme/themes.ts +149 -0
  500. package/src/tickers/search/index.ts +22 -2
  501. package/src/tickers/search/ranking.ts +45 -1
  502. package/src/tickers/search/types.ts +3 -1
  503. package/src/time-series/resolution.ts +15 -0
  504. package/src/time-series/resolve.ts +1 -14
  505. package/src/types/config.ts +61 -1
  506. package/src/types/financials.ts +32 -3
  507. package/src/types/headless.ts +11 -0
  508. package/src/types/instrument.ts +8 -0
  509. package/src/types/plugin.ts +49 -3
  510. package/src/ui/host.tsx +16 -0
  511. package/src/ui/index.tsx +10 -3
  512. package/src/ui/scroll-box-axis.ts +26 -0
  513. package/src/utils/cli-output.ts +14 -1
  514. package/src/utils/currency-units.ts +8 -3
  515. package/src/utils/depositary-receipt.ts +54 -10
  516. package/src/utils/display-number.ts +63 -0
  517. package/src/utils/exchanges.ts +13 -0
  518. package/src/utils/format.ts +2 -1
  519. package/src/utils/fundamentals.ts +17 -1
  520. package/src/utils/fx-market-hours.ts +34 -0
  521. package/src/utils/option-expiry.ts +126 -0
  522. package/src/utils/price-history-integrity.ts +19 -6
  523. package/src/utils/price-history.ts +39 -6
  524. package/src/utils/rpc-timeout-error.ts +6 -2
  525. package/src/utils/sec-eps-basis.ts +159 -30
  526. package/src/utils/sec.ts +38 -34
  527. package/src/utils/throttled-fetch.ts +51 -22
@@ -7,22 +7,39 @@ import { fetchTreasuryAuctions } from "./client";
7
7
  import { loadTreasuryAuctions, type TreasuryAuctionsResult } from "./cache";
8
8
  import type { TreasuryAuction } from "./types";
9
9
  import {
10
+ AUCTION_HISTORY_WINDOWS,
11
+ AUCTION_SEARCH_FIELDS,
12
+ auctionHistoryLabel,
13
+ auctionHistoryPhrase,
10
14
  auctionSize,
15
+ dealerPct,
11
16
  DEFAULT_AUCTION_SORT,
17
+ directPct,
12
18
  formatAuctionRate,
13
19
  indirectPct,
20
+ nextAuctionHistoryWindow,
14
21
  rateValue,
22
+ stopOutVsAverageBp,
15
23
  visibleAuctions,
16
24
  type AuctionFilter,
17
25
  } from "./model";
18
26
 
27
+ const formatPercent = (value: unknown) => value == null ? "-" : `${Number(value).toFixed(1)}%`;
28
+
29
+ /** Why the stop-out column is not a tail; the docs page says the same at length. */
30
+ const STOP_OUT_NOTE = "Stop-out vs avg is the high yield minus the average/median yield, in bp (bills: discount rates). "
31
+ + "A true tail, the stop-out against the 1 pm when-issued yield, needs the when-issued yield, which the source does not carry.";
32
+
19
33
  const COLUMNS = [
20
34
  { key: "auctionDate", header: "Date" },
21
35
  { key: "secType", header: "Type" },
22
36
  { key: "securityTerm", header: "Term" },
23
37
  { key: "rate", header: "Rate", align: "right" as const, format: (value: unknown, row: Record<string, unknown>) => formatAuctionRate(row as unknown as TreasuryAuction, value == null ? null : Number(value), "-") },
38
+ { key: "stopOutVsAvgBp", header: "Stop-out vs avg (bp)", align: "right" as const, format: (value: unknown) => value == null ? "-" : Number(value).toFixed(1) },
24
39
  { key: "bidToCoverRatio", header: "B/C", align: "right" as const, format: (value: unknown) => value == null ? "-" : Number(value).toFixed(2) },
25
- { key: "indirectPercent", header: "Indirect", align: "right" as const, format: (value: unknown) => value == null ? "-" : `${Number(value).toFixed(1)}%` },
40
+ { key: "indirectPercent", header: "Indirect", align: "right" as const, format: formatPercent },
41
+ { key: "directPercent", header: "Direct", align: "right" as const, format: formatPercent },
42
+ { key: "dealerPercent", header: "Dealer", align: "right" as const, format: formatPercent },
26
43
  { key: "size", header: "Size", align: "right" as const, format: (value: unknown) => value == null ? "-" : `$${formatCompact(Number(value))}` },
27
44
  { key: "cusip", header: "CUSIP" },
28
45
  ];
@@ -35,6 +52,13 @@ const defaultDependencies: TreasuryAuctionsHeadlessDependencies = {
35
52
  load: (_args, historyDays) => loadTreasuryAuctions(false, fetchTreasuryAuctions, historyDays),
36
53
  };
37
54
 
55
+ /** An empty table says what was searched, in which window, and what the search understands. */
56
+ function emptyNote(query: string, filter: AuctionFilter, historyDays: number): string {
57
+ const searched = query.trim() ? `match "${query.trim()}"` : "found";
58
+ const group = filter === "all" ? "" : ` in the ${filter} group`;
59
+ return `No auctions ${searched}${group} in ${auctionHistoryPhrase(historyDays)}. Search by ${AUCTION_SEARCH_FIELDS}.`;
60
+ }
61
+
38
62
  function createTreasuryAuctionsHeadless(
39
63
  dependencies: TreasuryAuctionsHeadlessDependencies = defaultDependencies,
40
64
  ): HeadlessPaneDefinition<"rows"> {
@@ -44,7 +68,7 @@ function createTreasuryAuctionsHeadless(
44
68
  argument: {
45
69
  kind: "free-text",
46
70
  placeholder: "search",
47
- description: "Optional security type, term, or auction date filter.",
71
+ description: "Optional search: security type, benchmark (10Y), term, CUSIP, or auction date (YYYY-MM-DD).",
48
72
  optional: true,
49
73
  },
50
74
  options: [
@@ -52,9 +76,9 @@ function createTreasuryAuctionsHeadless(
52
76
  key: "historyDays",
53
77
  aliases: ["history"],
54
78
  settingKey: "historyDays",
55
- description: "Auction history window in days.",
79
+ description: "Auction history window in days, up to 3650 (10 years).",
56
80
  type: "enum",
57
- values: [{ value: "30" }, { value: "90" }, { value: "120" }, { value: "365" }],
81
+ values: AUCTION_HISTORY_WINDOWS.map((days) => ({ value: String(days) })),
58
82
  defaultValue: "120",
59
83
  },
60
84
  {
@@ -77,13 +101,25 @@ function createTreasuryAuctionsHeadless(
77
101
  query,
78
102
  sort: DEFAULT_AUCTION_SORT,
79
103
  });
104
+ const nextWindow = nextAuctionHistoryWindow(historyDays);
105
+ const notes = [
106
+ ...(auctions.length === 0 ? [emptyNote(query, filter, historyDays)] : []),
107
+ nextWindow
108
+ ? `Older auctions: use --historyDays ${nextWindow}.`
109
+ : `Auctions older than ${auctionHistoryLabel(historyDays)} are not loaded.`,
110
+ ...(auctions.length > 0 ? [STOP_OUT_NOTE] : []),
111
+ ];
80
112
  return {
81
113
  complete: !result.refreshError,
82
114
  errors: result.refreshError ? [result.refreshError] : [],
115
+ notes,
83
116
  rows: auctions.map((auction) => ({
84
117
  ...auction,
85
118
  rate: rateValue(auction),
119
+ stopOutVsAvgBp: stopOutVsAverageBp(auction),
86
120
  indirectPercent: indirectPct(auction),
121
+ directPercent: directPct(auction),
122
+ dealerPercent: dealerPct(auction),
87
123
  size: auctionSize(auction),
88
124
  })),
89
125
  metadata: {
@@ -7,6 +7,7 @@ import {
7
7
  } from "./cache";
8
8
  import { TreasuryAuctionsPane } from "./pane";
9
9
  import { TREASURY_AUCTIONS_PANE_ID } from "./types";
10
+ import { AUCTION_HISTORY_WINDOWS, auctionHistoryLabel } from "./model";
10
11
  import { createPublicPaneShare } from "../shared/public-pane";
11
12
  import { treasuryAuctionsHeadless } from "./headless";
12
13
 
@@ -22,12 +23,7 @@ function treasuryAuctionsSettings(): PaneSettingsDef {
22
23
  label: "History window",
23
24
  description: "How far back auction results are requested.",
24
25
  type: "select",
25
- options: [
26
- { value: "30", label: "30 days" },
27
- { value: "90", label: "90 days" },
28
- { value: "120", label: "120 days" },
29
- { value: "365", label: "1 year" },
30
- ],
26
+ options: AUCTION_HISTORY_WINDOWS.map((days) => ({ value: String(days), label: auctionHistoryLabel(days) })),
31
27
  },
32
28
  ],
33
29
  };
@@ -40,7 +36,7 @@ export const treasuryAuctionsModule: PluginModule = {
40
36
  id: TREASURY_FISCAL_DATA_CONNECTION_ID,
41
37
  name: "Treasury Fiscal Data",
42
38
  kind: "api",
43
- ownerId: "macro",
39
+ ownerId: "credit",
44
40
  priority: 300,
45
41
  detail: "fiscaldata.treasury.gov",
46
42
  });
@@ -60,7 +56,7 @@ export const treasuryAuctionsModule: PluginModule = {
60
56
  component: TreasuryAuctionsPane,
61
57
  defaultPosition: "right",
62
58
  defaultMode: "floating",
63
- defaultFloatingSize: { width: 92, height: 28 },
59
+ defaultFloatingSize: { width: 104, height: 28 },
64
60
  tableExport: true,
65
61
  settings: treasuryAuctionsSettings(),
66
62
  },
@@ -72,7 +68,7 @@ export const treasuryAuctionsModule: PluginModule = {
72
68
  paneId: TREASURY_AUCTIONS_PANE_ID,
73
69
  label: "Treasury Auctions",
74
70
  description:
75
- "Bill, note, bond, and TIPS auction results from Treasury Fiscal Data: auction rate, bid-to-cover, indirect share, and size.",
71
+ "Bill, note, bond, and TIPS auction results from Treasury Fiscal Data: rate, stop-out versus average, bid-to-cover, indirect, direct and dealer takedown, and size. Search by benchmark (10Y) or CUSIP.",
76
72
  keywords: [
77
73
  "treasury",
78
74
  "auction",
@@ -85,6 +81,12 @@ export const treasuryAuctionsModule: PluginModule = {
85
81
  "bid",
86
82
  "cover",
87
83
  "indirect",
84
+ "takedown",
85
+ "tail",
86
+ "stop-out",
87
+ "stop out",
88
+ "cusip",
89
+ "reopening",
88
90
  "issuance",
89
91
  ],
90
92
  shortcut: { prefix: "AUCT" },
@@ -3,8 +3,36 @@ import { compareSortValues, type SortDirection } from "../../../utils/sort-value
3
3
  import { AUCTION_HISTORY_DAYS } from "./client";
4
4
  import type { TreasuryAuction } from "./types";
5
5
 
6
- /** Windows the Fiscal Data query supports without paging past MAX_PAGES. */
7
- const AUCTION_HISTORY_WINDOWS = [30, 90, 120, 365] as const;
6
+ /**
7
+ * History windows in days, ascending: 30 days to 10 years. Fiscal Data keeps
8
+ * auctions back to 1979, so these are our cap, and each one is walked as a
9
+ * paged query that stays inside the client's page bound.
10
+ */
11
+ export const AUCTION_HISTORY_WINDOWS = [30, 90, 120, 365, 1825, 3650] as const;
12
+
13
+ const AUCTION_HISTORY_LABELS: Record<number, { label: string; phrase: string }> = {
14
+ 30: { label: "30 days", phrase: "the last 30 days" },
15
+ 90: { label: "90 days", phrase: "the last 90 days" },
16
+ 120: { label: "120 days", phrase: "the last 120 days" },
17
+ 365: { label: "1 year", phrase: "the last year" },
18
+ 1825: { label: "5 years", phrase: "the last 5 years" },
19
+ 3650: { label: "10 years", phrase: "the last 10 years" },
20
+ };
21
+
22
+ /** The window as the settings menu names it: "120 days", "5 years". */
23
+ export function auctionHistoryLabel(days: number): string {
24
+ return AUCTION_HISTORY_LABELS[days]?.label ?? `${days} days`;
25
+ }
26
+
27
+ /** The window inside a sentence: "the last 120 days", "the last 5 years". */
28
+ export function auctionHistoryPhrase(days: number): string {
29
+ return AUCTION_HISTORY_LABELS[days]?.phrase ?? `the last ${days} days`;
30
+ }
31
+
32
+ /** The next longer window, or null when this one is already the longest. */
33
+ export function nextAuctionHistoryWindow(days: number): number | null {
34
+ return AUCTION_HISTORY_WINDOWS.find((window) => window > days) ?? null;
35
+ }
8
36
 
9
37
  /** Pane settings arrive as unvalidated strings, so anything unknown falls back. */
10
38
  export function auctionHistoryDays(settings: Record<string, unknown> | undefined): number {
@@ -12,7 +40,11 @@ export function auctionHistoryDays(settings: Record<string, unknown> | undefined
12
40
  return (AUCTION_HISTORY_WINDOWS as readonly number[]).includes(value) ? value : AUCTION_HISTORY_DAYS;
13
41
  }
14
42
 
15
- export type AuctionColumnId = "date" | "type" | "term" | "rate" | "btc" | "indirect" | "size";
43
+ /** What the search box understands, for empty results and the box's own prompt. */
44
+ export const AUCTION_SEARCH_FIELDS = "type, benchmark (10Y), term, CUSIP, or date (YYYY-MM-DD)";
45
+
46
+ export type AuctionColumnId =
47
+ | "date" | "type" | "term" | "rate" | "stopOut" | "btc" | "indirect" | "direct" | "dealer" | "size";
16
48
 
17
49
  export interface AuctionColumn extends DataTableColumn {
18
50
  id: AuctionColumnId;
@@ -33,8 +65,11 @@ export const AUCTION_SORT_COLUMN_IDS: readonly AuctionColumnId[] = [
33
65
  "type",
34
66
  "term",
35
67
  "rate",
68
+ "stopOut",
36
69
  "btc",
37
70
  "indirect",
71
+ "direct",
72
+ "dealer",
38
73
  "size",
39
74
  ];
40
75
 
@@ -64,16 +99,101 @@ export function nextFilter(current: AuctionFilter): AuctionFilter {
64
99
  return AUCTION_FILTERS[(index + 1) % AUCTION_FILTERS.length]!.value;
65
100
  }
66
101
 
67
- function matchesAuctionQuery(auction: TreasuryAuction, query: string): boolean {
68
- const normalized = query.trim().toLowerCase();
69
- if (!normalized) return true;
102
+ type TermUnit = "year" | "month" | "week" | "day";
103
+ type TermParts = Partial<Record<TermUnit, number>>;
104
+
105
+ /** "29-Year 10-Month" as { year: 29, month: 10 }; null for a term this does not recognize. */
106
+ function termParts(term: string): TermParts | null {
107
+ const pattern = /(\d+)\s*-\s*(Day|Week|Month|Year)/gi;
108
+ const components = [...term.matchAll(pattern)];
109
+ if (!components.length || term.replace(pattern, "").trim()) return null;
110
+ const parts: TermParts = {};
111
+ for (const match of components) {
112
+ const unit = match[2]!.toLowerCase() as TermUnit;
113
+ parts[unit] = (parts[unit] ?? 0) + Number(match[1]);
114
+ }
115
+ return parts;
116
+ }
117
+
118
+ interface Benchmark {
119
+ unit: TermUnit;
120
+ count: number;
121
+ }
122
+
123
+ /**
124
+ * The benchmark an auction was sold as. Treasury reopens a security with the
125
+ * term it has left, a month or two after issue: the 10-year note comes back as
126
+ * 9-Year 10-Month, the 30-year bond as 29-Year 10-Month, the 2-year FRN as
127
+ * 1-Year 11-Month. Any term with a year part therefore rounds up to the next
128
+ * whole year; a bill or CMB term (weeks, days) is its own benchmark. The term
129
+ * at auction is what the market calls the auction, so a 5-year auction that
130
+ * reopens an older 7-year note is still the 5Y.
131
+ */
132
+ function auctionBenchmark(term: string): Benchmark | null {
133
+ const parts = termParts(term);
134
+ if (!parts) return null;
135
+ if (parts.year) {
136
+ return { unit: "year", count: parts.year + (parts.month || parts.week || parts.day ? 1 : 0) };
137
+ }
138
+ const units = Object.keys(parts) as TermUnit[];
139
+ return units.length === 1 ? { unit: units[0]!, count: parts[units[0]!]! } : null;
140
+ }
141
+
142
+ const BENCHMARK_QUERY = /^(\d{1,3}) ?-? ?(y|yr|yrs|years?|m|mo|mos|months?|w|wk|wks|weeks?|d|days?)$/;
143
+
144
+ /** "10Y", "10yr", "10-year" and "10 year" all name the 10-year benchmark. */
145
+ function parseBenchmarkQuery(query: string): Benchmark | null {
146
+ const match = BENCHMARK_QUERY.exec(query);
147
+ if (!match) return null;
148
+ const unit: TermUnit = match[2]![0] === "y" ? "year" : match[2]![0] === "m" ? "month" : match[2]![0] === "w" ? "week" : "day";
149
+ return { unit, count: Number(match[1]) };
150
+ }
151
+
152
+ /**
153
+ * Words that name a security type. A benchmark search leaves TIPS and FRNs
154
+ * out, because "10Y" means the 10-year note and a 10-year TIPS or the FRN that
155
+ * reopens as 1-Year 11-Month would bury it; "10Y TIPS" asks for them.
156
+ */
157
+ const TYPE_WORDS: ReadonlyMap<string, string> = new Map([
158
+ ["bill", "bill"], ["bills", "bill"], ["note", "note"], ["notes", "note"], ["bond", "bond"], ["bonds", "bond"],
159
+ ["tips", "tips"], ["frn", "frn"], ["frns", "frn"], ["cmb", "cmb"], ["cmbs", "cmb"],
160
+ ]);
161
+
162
+ /** A partial CUSIP: four or more letters and digits with a digit, so "bill" or "2y" never read as one. */
163
+ function isCusipQuery(query: string): boolean {
164
+ return /^[a-z0-9]{4,9}$/.test(query) && /\d/.test(query);
165
+ }
166
+
167
+ function matchesQueryText(auction: TreasuryAuction, text: string, typeNamed: boolean): boolean {
168
+ const benchmark = parseBenchmarkQuery(text);
169
+ if (benchmark) {
170
+ if (!typeNamed && (auction.secType === "TIPS" || auction.secType === "FRN")) return false;
171
+ // The benchmark it was sold as ("10Y" finds 9-Year 10-Month) or a part of
172
+ // its term as written ("9-year" finds the same reopening, "10-month" too).
173
+ const own = auctionBenchmark(auction.securityTerm);
174
+ const parts = termParts(auction.securityTerm);
175
+ return (own?.unit === benchmark.unit && own.count === benchmark.count) || parts?.[benchmark.unit] === benchmark.count;
176
+ }
70
177
  return (
71
- auction.secType.toLowerCase().includes(normalized)
72
- || auction.securityTerm.toLowerCase().includes(normalized)
73
- || auction.auctionDate.includes(normalized)
178
+ auction.secType.toLowerCase().includes(text)
179
+ || auction.securityTerm.toLowerCase().includes(text)
180
+ || auction.auctionDate.includes(text)
181
+ || (isCusipQuery(text) && !!auction.cusip?.toLowerCase().includes(text))
74
182
  );
75
183
  }
76
184
 
185
+ function matchesAuctionQuery(auction: TreasuryAuction, query: string): boolean {
186
+ const normalized = query.trim().toLowerCase().replace(/\s+/g, " ");
187
+ if (!normalized) return true;
188
+ if (matchesQueryText(auction, normalized, false)) return true;
189
+ // "10Y TIPS" or "tips 10-year": a type word plus the rest of the search.
190
+ const words = normalized.split(" ");
191
+ const typeIndex = words.findIndex((word) => TYPE_WORDS.has(word));
192
+ if (typeIndex < 0 || auction.secType.toLowerCase() !== TYPE_WORDS.get(words[typeIndex]!)) return false;
193
+ const rest = words.filter((_, index) => index !== typeIndex).join(" ");
194
+ return !rest || matchesQueryText(auction, rest, true);
195
+ }
196
+
77
197
  function auctionDateValue(value: string): number {
78
198
  const timestamp = Date.parse(`${value}T00:00:00Z`);
79
199
  return Number.isFinite(timestamp) ? timestamp : 0;
@@ -95,15 +215,49 @@ export function termLengthDays(term: string): number {
95
215
  }, 0);
96
216
  }
97
217
 
218
+ /** A bidder class's accepted dollars as a share of competitive accepted, which excludes noncompetitive, FIMA and SOMA add-on awards. */
219
+ function competitiveSharePct(accepted: number | null, auction: TreasuryAuction): number | null {
220
+ if (accepted == null || !auction.competitiveAccepted) return null;
221
+ return (accepted / auction.competitiveAccepted) * 100;
222
+ }
223
+
98
224
  /**
99
- * Indirect takedown, as Treasury reports it: a share of competitive accepted,
100
- * which excludes noncompetitive, FIMA and SOMA add-on awards. Zero indirect
101
- * bidding is a real, and notable, outcome, so only a missing leg or an
102
- * unusable total is unknown.
225
+ * Indirect takedown, as Treasury reports it: a share of competitive accepted.
226
+ * Zero indirect bidding is a real, and notable, outcome, so only a missing leg
227
+ * or an unusable total is unknown.
103
228
  */
104
229
  export function indirectPct(auction: TreasuryAuction): number | null {
105
- if (auction.indirectAccepted == null || !auction.competitiveAccepted) return null;
106
- return (auction.indirectAccepted / auction.competitiveAccepted) * 100;
230
+ return competitiveSharePct(auction.indirectAccepted, auction);
231
+ }
232
+
233
+ /** Direct takedown, on the same denominator as indirectPct. */
234
+ export function directPct(auction: TreasuryAuction): number | null {
235
+ return competitiveSharePct(auction.directAccepted, auction);
236
+ }
237
+
238
+ /** Primary dealer takedown, on the same denominator as indirectPct. */
239
+ export function dealerPct(auction: TreasuryAuction): number | null {
240
+ return competitiveSharePct(auction.primaryDealerAccepted, auction);
241
+ }
242
+
243
+ /**
244
+ * The stop-out (high yield) minus the average/median yield Treasury publishes
245
+ * for the same auction, in basis points; a wider gap means the last dollars
246
+ * had to clear well above where most of the auction priced. Bills compare
247
+ * discount rates, which is how they trade. FRNs and auctions missing either
248
+ * leg are null.
249
+ *
250
+ * This is not a tail: a tail is the stop-out against the 1 pm when-issued
251
+ * yield, which the source does not carry.
252
+ */
253
+ export function stopOutVsAverageBp(auction: TreasuryAuction): number | null {
254
+ if (auction.secType === "FRN") return null;
255
+ const bill = FILTER_TYPES.bill.has(auction.secType);
256
+ const high = bill ? auction.highDiscountRate : auction.highYield;
257
+ const average = bill ? auction.avgMedDiscountRate : auction.avgMedYield;
258
+ if (high == null || average == null) return null;
259
+ // Rates arrive to three decimals, so hundredths of a basis point only hide float noise.
260
+ return Math.round((high - average) * 100 * 100) / 100;
107
261
  }
108
262
 
109
263
  /**
@@ -149,8 +303,11 @@ function sortValue(auction: TreasuryAuction, columnId: AuctionColumnId): number
149
303
  return days === Number.MAX_SAFE_INTEGER ? null : days;
150
304
  }
151
305
  case "rate": return rateValue(auction);
306
+ case "stopOut": return stopOutVsAverageBp(auction);
152
307
  case "btc": return auction.bidToCoverRatio;
153
308
  case "indirect": return indirectPct(auction);
309
+ case "direct": return directPct(auction);
310
+ case "dealer": return dealerPct(auction);
154
311
  case "size": return auctionSize(auction);
155
312
  }
156
313
  }
@@ -180,21 +337,31 @@ export function firstAuctionSortDirection(columnId: AuctionColumnId): SortDirect
180
337
  return columnId === "type" || columnId === "term" ? "asc" : "desc";
181
338
  }
182
339
 
183
- /** TERM takes the spare width; the table adds the gaps and header room itself. */
184
- export function buildAuctionColumns(): AuctionColumn[] {
185
- const dateWidth = 8;
186
- const typeWidth = 6;
187
- const rateWidth = 8;
188
- const btcWidth = 6;
189
- const indirectWidth = 9;
190
- const sizeWidth = 8;
340
+ /**
341
+ * "Oct 13" is ambiguous once a window spans years, so a window past a year
342
+ * dates its rows in full (2026-10-13), the way the search takes a date.
343
+ */
344
+ export function auctionDatesShowYear(historyDays: number): boolean {
345
+ return historyDays > 365;
346
+ }
347
+
348
+ /**
349
+ * Widths are the data's own; the table widens a column to its label plus the
350
+ * sort arrow. All ten columns then take 93 cells. TERM takes the spare width
351
+ * but never less than the longest term ("29-Year 10-Month"), so a narrower
352
+ * pane scrolls sideways instead of clipping it.
353
+ */
354
+ export function buildAuctionColumns(showYear = false): AuctionColumn[] {
191
355
  return [
192
- { id: "date", label: "DATE", width: dateWidth, align: "left" },
193
- { id: "type", label: "TYPE", width: typeWidth, align: "left" },
194
- { id: "term", label: "TERM", width: 10, align: "left", flexGrow: 1 },
195
- { id: "rate", label: "RATE", width: rateWidth, align: "right" },
196
- { id: "btc", label: "B/C", width: btcWidth, align: "right" },
197
- { id: "indirect", label: "INDIRECT", width: indirectWidth, align: "right" },
198
- { id: "size", label: "SIZE", width: sizeWidth, align: "right" },
356
+ { id: "date", label: "DATE", width: showYear ? 10 : 6, align: "left" },
357
+ { id: "type", label: "TYPE", width: 6, align: "left" },
358
+ { id: "term", label: "TERM", width: 16, align: "left", flexGrow: 1 },
359
+ { id: "rate", label: "RATE", width: 7, align: "right" },
360
+ { id: "stopOut", label: "VS AVG", width: 7, align: "right" },
361
+ { id: "btc", label: "B/C", width: 5, align: "right" },
362
+ { id: "indirect", label: "INDIRECT", width: 8, align: "right" },
363
+ { id: "direct", label: "DIRECT", width: 6, align: "right" },
364
+ { id: "dealer", label: "DEALER", width: 6, align: "right" },
365
+ { id: "size", label: "SIZE", width: 7, align: "right" },
199
366
  ];
200
367
  }
@@ -28,11 +28,16 @@ import { useAutoRefresh } from "../../../react/auto-refresh";
28
28
  import { loadTreasuryAuctions } from "./cache";
29
29
  import {
30
30
  AUCTION_FILTERS,
31
+ AUCTION_SEARCH_FIELDS,
31
32
  AUCTION_SORT_COLUMN_IDS,
32
33
  DEFAULT_AUCTION_SORT,
34
+ auctionDatesShowYear,
33
35
  auctionHistoryDays,
36
+ auctionHistoryPhrase,
34
37
  auctionSize,
35
38
  buildAuctionColumns,
39
+ dealerPct,
40
+ directPct,
36
41
  firstAuctionSortDirection,
37
42
  formatAuctionRate,
38
43
  indirectPct,
@@ -40,6 +45,7 @@ import {
40
45
  nextFilter,
41
46
  rateLabel,
42
47
  rateValue,
48
+ stopOutVsAverageBp,
43
49
  visibleAuctions,
44
50
  type AuctionColumn,
45
51
  type AuctionColumnId,
@@ -63,6 +69,11 @@ function formatPct(value: number | null): string {
63
69
  return value == null ? "—" : `${value.toFixed(1)}%`;
64
70
  }
65
71
 
72
+ /** The stop-out against the average reads in basis points, like an FRN margin. */
73
+ function formatBp(value: number | null): string {
74
+ return value == null ? "—" : `${value.toFixed(1)}bp`;
75
+ }
76
+
66
77
  function formatMoney(value: number | null): string {
67
78
  return value == null ? "—" : `$${formatCompact(value)}`;
68
79
  }
@@ -84,19 +95,14 @@ function secTypeColor(secType: string, selected: boolean): string {
84
95
  }
85
96
  }
86
97
 
87
- // Stable table adapters so memoized rows survive pane re-renders.
98
+ // Stable table adapter so memoized rows survive pane re-renders.
88
99
  const auctionKey = (auction: TreasuryAuction) => auction.id;
89
- const renderAuctionRow = (
90
- auction: TreasuryAuction,
91
- column: AuctionColumn,
92
- _index: number,
93
- rowState: { selected: boolean },
94
- ) => renderAuctionCell(auction, column, rowState);
95
100
 
96
101
  function renderAuctionCell(
97
102
  auction: TreasuryAuction,
98
103
  column: AuctionColumn,
99
104
  rowState: { selected: boolean },
105
+ showYear: boolean,
100
106
  ): DataTableCell {
101
107
  const selected = rowState.selected ? colors.selectedText : undefined;
102
108
  const dimmed = selected ?? colors.textDim;
@@ -106,7 +112,7 @@ function renderAuctionCell(
106
112
  // Announced auctions have no results yet; every metric cell reads "—",
107
113
  // so the date carries the distinction instead of a second placeholder.
108
114
  return {
109
- text: formatShortDate(auction.auctionDate, { year: false, utc: true, fallback: "\u2014" }),
115
+ text: showYear ? auction.auctionDate : formatShortDate(auction.auctionDate, { year: false, utc: true, fallback: "\u2014" }),
110
116
  color: rowState.selected ? colors.selectedText : isPendingAuction(auction) ? colors.textBright : colors.textDim,
111
117
  };
112
118
  case "type":
@@ -119,10 +125,16 @@ function renderAuctionCell(
119
125
  return { text: auction.securityTerm, color: selected ?? colors.text };
120
126
  case "rate":
121
127
  return { text: formatAuctionRate(auction, rateValue(auction), "—"), color: selected ?? colors.textBright };
128
+ case "stopOut":
129
+ return { text: formatBp(stopOutVsAverageBp(auction)), color: selected ?? colors.text };
122
130
  case "btc":
123
131
  return { text: formatRatio(auction.bidToCoverRatio), color: selected ?? colors.text };
124
132
  case "indirect":
125
133
  return { text: formatPct(indirectPct(auction)), color: selected ?? colors.text };
134
+ case "direct":
135
+ return { text: formatPct(directPct(auction)), color: selected ?? colors.text };
136
+ case "dealer":
137
+ return { text: formatPct(dealerPct(auction)), color: selected ?? colors.text };
126
138
  case "size":
127
139
  return { text: formatMoney(auctionSize(auction)), color: dimmed };
128
140
  }
@@ -140,12 +152,16 @@ function TreasuryAuctionDetail({ auction, width }: { auction: TreasuryAuction; w
140
152
  <Box flexDirection="row" height={1} gap={2}>
141
153
  <Text fg={colors.textDim}>{formatShortDate(auction.auctionDate, { utc: true, fallback: "\u2014" })}</Text>
142
154
  {isPendingAuction(auction) && <Text fg={colors.textDim}>results pending</Text>}
155
+ {auction.cusip && <Text fg={colors.textDim}>{auction.cusip}</Text>}
143
156
  </Box>
144
157
  <Box height={1} />
145
158
  <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label={rateLabel(auction)} value={formatAuctionRate(auction, rateValue(auction), "—")} />
146
159
  {auction.avgMedYield != null && (
147
160
  <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="Median yield" value={formatRate(auction.avgMedYield)} />
148
161
  )}
162
+ {stopOutVsAverageBp(auction) != null && (
163
+ <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="Stop-out vs average" value={formatBp(stopOutVsAverageBp(auction))} />
164
+ )}
149
165
  <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="Bid-to-cover" value={formatRatio(auction.bidToCoverRatio)} />
150
166
  <Box height={1} />
151
167
  <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="High price" value={auction.highPrice?.toFixed(4) ?? "—"} />
@@ -156,6 +172,7 @@ function TreasuryAuctionDetail({ auction, width }: { auction: TreasuryAuction; w
156
172
  <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="Total accepted" value={formatMoney(auction.totalAccepted)} />
157
173
  <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="Competitive" value={share(auction.competitiveAccepted, auction.totalAccepted)} />
158
174
  <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="Indirect" value={share(auction.indirectAccepted, auction.competitiveAccepted)} />
175
+ <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="Direct" value={share(auction.directAccepted, auction.competitiveAccepted)} />
159
176
  <KeyValueRow labelWidth={22} width={Math.max(1, width - 2)} emphasis={false} label="Primary dealer" value={share(auction.primaryDealerAccepted, auction.competitiveAccepted)} />
160
177
  </Box>
161
178
  </ScrollBox>
@@ -252,7 +269,14 @@ export function TreasuryAuctionsPane({ focused, width, height }: PaneProps) {
252
269
  return handlePaneKey(event);
253
270
  }, [focusSearch, handlePaneKey]);
254
271
 
255
- const columns = useMemo(() => buildAuctionColumns(), []);
272
+ const showYear = auctionDatesShowYear(historyDays);
273
+ const columns = useMemo(() => buildAuctionColumns(showYear), [showYear]);
274
+ const renderAuctionRow = useCallback((
275
+ auction: TreasuryAuction,
276
+ column: AuctionColumn,
277
+ _index: number,
278
+ rowState: { selected: boolean },
279
+ ) => renderAuctionCell(auction, column, rowState, showYear), [showYear]);
256
280
 
257
281
  usePaneFooter(TREASURY_AUCTIONS_PANE_ID, () => {
258
282
  const info = loadingErrorFooterInfo(loading, error);
@@ -335,7 +359,7 @@ export function TreasuryAuctionsPane({ focused, width, height }: PaneProps) {
335
359
  search={{
336
360
  value: searchQuery,
337
361
  onChange: setSearchQuery,
338
- placeholder: "type, term, or date",
362
+ placeholder: "type, 10Y, CUSIP, or date",
339
363
  focused: focused && !detailOpen,
340
364
  ...searchProps,
341
365
  }}
@@ -365,7 +389,7 @@ export function TreasuryAuctionsPane({ focused, width, height }: PaneProps) {
365
389
  getItemKey={auctionKey}
366
390
  renderCell={renderAuctionRow}
367
391
  emptyStateTitle={searchQuery.trim() ? "No matching auctions." : "No recent auctions."}
368
- emptyStateHint={searchQuery.trim() ? "Clear search." : undefined}
392
+ emptyStateHint={`${searchQuery.trim() ? "Searched" : "Showing"} ${auctionHistoryPhrase(historyDays)}; older auctions are in the History window setting. Search by ${AUCTION_SEARCH_FIELDS}.`}
369
393
  />
370
394
  </Box>
371
395
  );
@@ -20,8 +20,13 @@ export interface TreasuryAuction {
20
20
  highInvestmentRate: number | null;
21
21
  /** FRN high discount margin over the 13-week bill index, in percentage points. */
22
22
  highDiscountMargin?: number | null;
23
- /** High yield, reported by Notes, Bonds, and TIPS. */
23
+ /** Bill high (stop-out) discount rate, in percentage points. */
24
+ highDiscountRate: number | null;
25
+ /** Bill average discount rate, in percentage points. */
26
+ avgMedDiscountRate: number | null;
27
+ /** High (stop-out) yield, reported by Notes, Bonds, and TIPS. */
24
28
  highYield: number | null;
29
+ /** Median yield for notes, bonds and TIPS, as Treasury publishes it. */
25
30
  avgMedYield: number | null;
26
31
  highPrice: number | null;
27
32
  lowPrice: number | null;
@@ -31,6 +36,8 @@ export interface TreasuryAuction {
31
36
  competitiveAccepted: number | null;
32
37
  /** Indirect bidder accepted dollars, including customers bidding through direct submitters. */
33
38
  indirectAccepted: number | null;
39
+ /** Direct bidder accepted dollars: investors bidding for their own account. */
40
+ directAccepted: number | null;
34
41
  /** Primary dealer accepted dollars. */
35
42
  primaryDealerAccepted: number | null;
36
43
  totalAccepted: number | null;
@@ -53,10 +60,13 @@ export interface TreasuryAuctionRaw {
53
60
  bid_to_cover_ratio?: string;
54
61
  comp_accepted?: string;
55
62
  indirect_bidder_accepted?: string;
63
+ direct_bidder_accepted?: string;
56
64
  primary_dealer_accepted?: string;
57
65
  total_accepted?: string;
58
66
  offering_amt?: string;
59
67
  inflation_index_security?: string;
60
68
  floating_rate?: string;
61
69
  high_discnt_margin?: string;
70
+ high_discnt_rate?: string;
71
+ avg_med_discnt_rate?: string;
62
72
  }
@@ -6,10 +6,8 @@ import { useThemeColors } from "../../../theme/theme-context";
6
6
  import { Box, ScrollBox, Text } from "../../../ui";
7
7
  import { evaluateSmile, optionDelta } from "../shared/volatility";
8
8
  import { buildSurfaceGrid, evaluateSurfaceSmile, type SurfaceExpiry, type SurfaceSnapshot } from "./model";
9
+ import { expiryLabel, formatPrice } from "./tables";
9
10
 
10
- export const formatIv = (value: number | null | undefined) => value == null || !Number.isFinite(value) ? "--" : `${(value * 100).toFixed(2)}%`;
11
- export const formatPrice = (value: number | null | undefined) => value == null || !Number.isFinite(value) ? "--" : value.toFixed(2);
12
- export const expiryLabel = (expiration: number) => new Date(expiration * 1000).toISOString().slice(0, 10);
13
11
  const point = (x: number, y: number): ProjectedChartPoint => ({ date: new Date(Math.round(x * 1_000_000)), open: y, high: y, low: y, close: y, volume: 0 });
14
12
 
15
13
  export function SmileChart({ snapshot, expiry, overlay, axis, width, height, focused = false }: {