gloomberb 0.11.2 → 0.12.0

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 (531) hide show
  1. package/README.md +7 -4
  2. package/README.zh-CN.md +4 -2
  3. package/package.json +28 -1
  4. package/src/api-client/auth.ts +10 -0
  5. package/src/api-client/data.ts +108 -1
  6. package/src/api-client/index.test.ts +127 -0
  7. package/src/api-client/index.ts +134 -1
  8. package/src/api-client/normalizers.ts +39 -0
  9. package/src/api-client/paths.ts +85 -1
  10. package/src/api-client/types.ts +220 -0
  11. package/src/app/pane-runtime/index.tsx +15 -12
  12. package/src/app/pane-runtime/layout-placement.test.ts +27 -0
  13. package/src/app/pane-runtime/layout-placement.ts +13 -0
  14. package/src/app/pane-runtime/plugin-bindings.ts +62 -0
  15. package/src/app.tsx +60 -18
  16. package/src/architecture/browser-entry-graph.test.ts +96 -0
  17. package/src/brokers/profile-form.test.ts +25 -27
  18. package/src/brokers/test-broker.ts +68 -0
  19. package/src/capabilities/chart-series.ts +3 -2
  20. package/src/cli/commands/market.ts +2 -2
  21. package/src/cli/commands/plugins.ts +39 -11
  22. package/src/cli/desktop-pane-shot.ts +285 -16
  23. package/src/cli/index.ts +1 -1
  24. package/src/cli/pane-functions/capabilities.ts +61 -31
  25. package/src/cli/pane-functions/catalog.ts +16 -4
  26. package/src/cli/pane-functions/discovery.ts +1 -0
  27. package/src/cli/pane-functions/headless.test.ts +247 -0
  28. package/src/cli/pane-functions/headless.ts +423 -0
  29. package/src/cli/pane-functions/index.test.ts +9 -0
  30. package/src/cli/pane-functions/index.ts +6 -2
  31. package/src/cli/pane-functions/options.ts +27 -2
  32. package/src/cli/pane-functions/report.ts +4 -0
  33. package/src/cli/pane-functions/resolver.ts +26 -8
  34. package/src/cli/pane-functions/screenshot.test.ts +76 -0
  35. package/src/cli/pane-functions/screenshot.ts +236 -20
  36. package/src/cli/registry.ts +0 -22
  37. package/src/cli/restore-plugins.ts +34 -0
  38. package/src/cli/result.ts +7 -10
  39. package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
  40. package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
  41. package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
  42. package/src/components/chart/composite/composite-chart.test.tsx +68 -20
  43. package/src/components/chart/composite/composite-chart.tsx +301 -204
  44. package/src/components/chart/composite/format.ts +8 -2
  45. package/src/components/chart/composite/interactions.test.ts +68 -102
  46. package/src/components/chart/composite/interactions.ts +214 -264
  47. package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
  48. package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
  49. package/src/components/chart/composite/scene.ts +57 -3
  50. package/src/components/chart/composite/text-renderer.ts +3 -2
  51. package/src/components/chart/composite/time-scale.ts +138 -57
  52. package/src/components/chart/composite/types.ts +25 -1
  53. package/src/components/chart/core/data.ts +9 -13
  54. package/src/components/chart/core/date-window.ts +7 -1
  55. package/src/components/chart/core/pointer.ts +3 -0
  56. package/src/components/chart/core/types.ts +0 -45
  57. package/src/components/chart/native/chart-rasterizer.ts +0 -1
  58. package/src/components/chart/native/kitty/index.test.ts +0 -188
  59. package/src/components/chart/native/raster/crosshair.ts +6 -5
  60. package/src/components/chart/native/raster/primitives.ts +0 -23
  61. package/src/components/chart/native/renderer-selection.ts +81 -31
  62. package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
  63. package/src/components/chart/static/chart-surface.tsx +150 -0
  64. package/src/components/chart/static/index.ts +8 -0
  65. package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
  66. package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
  67. package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
  68. package/src/components/chart/static/series.ts +49 -0
  69. package/src/components/command-bar/action-runtime.ts +1 -3
  70. package/src/components/command-bar/assist/model.test.ts +17 -2
  71. package/src/components/command-bar/assist/model.ts +40 -9
  72. package/src/components/command-bar/commands/direct/index.ts +1 -1
  73. package/src/components/command-bar/commands/direct/runtime.ts +1 -1
  74. package/src/components/command-bar/commands/registry.ts +0 -11
  75. package/src/components/command-bar/helpers.test.ts +2 -2
  76. package/src/components/command-bar/helpers.ts +2 -6
  77. package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
  78. package/src/components/command-bar/list/badge.test.ts +54 -0
  79. package/src/components/command-bar/list/badge.ts +62 -0
  80. package/src/components/command-bar/list/model.test.ts +103 -0
  81. package/src/components/command-bar/list/model.ts +61 -4
  82. package/src/components/command-bar/list/view.test.tsx +113 -0
  83. package/src/components/command-bar/list/view.tsx +147 -131
  84. package/src/components/command-bar/pane-templates/workflow.ts +1 -1
  85. package/src/components/command-bar/panel/body.tsx +51 -65
  86. package/src/components/command-bar/panel/index.tsx +48 -13
  87. package/src/components/command-bar/panel/layout.test.ts +139 -0
  88. package/src/components/command-bar/panel/layout.ts +65 -28
  89. package/src/components/command-bar/panel/native-surface.ts +24 -0
  90. package/src/components/command-bar/panel/prompt-binding.ts +54 -0
  91. package/src/components/command-bar/panel/runtime.ts +6 -3
  92. package/src/components/command-bar/panel/state.ts +41 -7
  93. package/src/components/command-bar/panel/types.ts +7 -1
  94. package/src/components/command-bar/routes/root/provider-search.ts +34 -15
  95. package/src/components/command-bar/routes/root/results.test.ts +161 -0
  96. package/src/components/command-bar/routes/root/results.ts +30 -28
  97. package/src/components/command-bar/routes/root/runtime.ts +37 -20
  98. package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
  99. package/src/components/command-bar/routes/root/search-providers.ts +205 -0
  100. package/src/components/command-bar/routes/root/selection.ts +1 -12
  101. package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
  102. package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
  103. package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
  104. package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
  105. package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
  106. package/src/components/command-bar/routing/actions.ts +1 -81
  107. package/src/components/command-bar/routing/launch-request.ts +1 -1
  108. package/src/components/command-bar/routing/list-state.ts +6 -21
  109. package/src/components/command-bar/selection-runtime.ts +1 -1
  110. package/src/components/command-bar/surface/assist.test.tsx +14 -10
  111. package/src/components/command-bar/surface/environment.ts +8 -1
  112. package/src/components/command-bar/surface/index.test.tsx +84 -68
  113. package/src/components/command-bar/surface/index.tsx +33 -36
  114. package/src/components/command-bar/surface/test-harness.tsx +15 -3
  115. package/src/components/command-bar/theme-picker.tsx +43 -15
  116. package/src/components/command-bar/view-model.test.ts +53 -8
  117. package/src/components/command-bar/view-model.ts +43 -14
  118. package/src/components/command-bar/workflow/tickers.ts +1 -0
  119. package/src/components/command-bar/workflow/types.ts +1 -1
  120. package/src/components/data-table/export.test.ts +21 -0
  121. package/src/components/data-table/export.ts +21 -0
  122. package/src/components/data-table/view.test.tsx +45 -6
  123. package/src/components/data-table/view.tsx +55 -9
  124. package/src/components/index.ts +10 -2
  125. package/src/components/input-search-bar.test.tsx +36 -2
  126. package/src/components/input-search-bar.tsx +18 -1
  127. package/src/components/layout/header.test.tsx +57 -10
  128. package/src/components/layout/header.tsx +292 -149
  129. package/src/components/layout/market-summary.test.ts +81 -0
  130. package/src/components/layout/market-summary.ts +109 -0
  131. package/src/components/layout/shell/chrome.ts +96 -1
  132. package/src/components/layout/shell/index.tsx +11 -3
  133. package/src/components/layout/shell/menu.ts +9 -0
  134. package/src/components/layout/shell/pane/actions.ts +29 -0
  135. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  136. package/src/components/layout/shell/shortcuts.ts +3 -0
  137. package/src/components/layout/status-bar.test.tsx +9 -8
  138. package/src/components/layout/status-bar.tsx +85 -54
  139. package/src/components/onboarding/onboarding-frame.tsx +2 -26
  140. package/src/components/price-sparkline/index.ts +61 -34
  141. package/src/components/price-sparkline/view.tsx +1 -1
  142. package/src/components/sign-in-gate.test.tsx +128 -0
  143. package/src/components/sign-in-gate.tsx +149 -0
  144. package/src/components/speedometer-gauge/desktop.tsx +2 -12
  145. package/src/components/ticker/badge/list.tsx +17 -3
  146. package/src/components/ticker/list-table-view.tsx +6 -3
  147. package/src/components/ui/data-table/index.tsx +22 -4
  148. package/src/components/ui/data-table/opentui/index.tsx +165 -120
  149. package/src/components/ui/frame.tsx +28 -0
  150. package/src/components/ui/index.ts +3 -0
  151. package/src/components/ui/native-select.tsx +20 -10
  152. package/src/components/ui/select-button.tsx +138 -0
  153. package/src/components/ui/status.tsx +2 -2
  154. package/src/components/ui/table-layout.ts +1 -1
  155. package/src/components/use-double-click-activation.ts +7 -3
  156. package/src/core/app-services.ts +3 -3
  157. package/src/data/config/chart-settings.ts +4 -4
  158. package/src/data/config/layout.ts +12 -6
  159. package/src/data/config/store/index.test.ts +97 -0
  160. package/src/data/config/store/migrations.ts +41 -0
  161. package/src/data/config/store/normalize.ts +5 -3
  162. package/src/i18n/es.ts +6 -2
  163. package/src/i18n/ja.ts +6 -2
  164. package/src/i18n/ko.ts +6 -2
  165. package/src/i18n/zh-cn.ts +6 -2
  166. package/src/i18n/zh-tw.ts +6 -2
  167. package/src/layout-marketplace/gallery-terminal.tsx +126 -96
  168. package/src/layout-marketplace/gallery.test.tsx +65 -1
  169. package/src/layout-marketplace/pane-imagery.ts +1 -0
  170. package/src/layout-marketplace/payload.test.ts +17 -0
  171. package/src/layout-marketplace/payload.ts +40 -5
  172. package/src/market-data/coordinator/index.ts +3 -2
  173. package/src/market-data/coordinator/quotes.ts +173 -66
  174. package/src/market-data/coordinator/subscriptions.test.ts +215 -37
  175. package/src/pane-settings.ts +1 -1
  176. package/src/plugins/builtin/analytics/pane-model.ts +1 -1
  177. package/src/plugins/builtin/analytics/view.tsx +1 -1
  178. package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
  179. package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
  180. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
  181. package/src/plugins/builtin/chart-composer/cli-options.ts +12 -9
  182. package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
  183. package/src/plugins/builtin/chart-composer/settings.ts +2 -13
  184. package/src/plugins/builtin/chat/content/composer.tsx +8 -4
  185. package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
  186. package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
  187. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  188. package/src/plugins/builtin/composite-plugins.ts +16 -1
  189. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  190. package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
  191. package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
  192. package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
  193. package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
  194. package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
  195. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  196. package/src/plugins/builtin/earnings/index.tsx +1 -0
  197. package/src/plugins/builtin/earnings-calls/data.ts +223 -0
  198. package/src/plugins/builtin/earnings-calls/format.ts +49 -0
  199. package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
  200. package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
  201. package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
  202. package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
  203. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
  204. package/src/plugins/builtin/econ/detail-view.tsx +1 -2
  205. package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
  206. package/src/plugins/builtin/econ/index.tsx +3 -1
  207. package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
  208. package/src/plugins/builtin/econ-statistics/client.ts +92 -0
  209. package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
  210. package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
  211. package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
  212. package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
  213. package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
  214. package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
  215. package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
  216. package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
  217. package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
  218. package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
  219. package/src/plugins/builtin/econ-statistics/view.ts +90 -0
  220. package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
  221. package/src/plugins/builtin/fear-greed/data.ts +6 -1
  222. package/src/plugins/builtin/futures/index.tsx +1 -0
  223. package/src/plugins/builtin/fx-matrix/index.tsx +1 -0
  224. package/src/plugins/builtin/help/index.tsx +4 -0
  225. package/src/plugins/builtin/holders/index.tsx +1 -0
  226. package/src/plugins/builtin/insider/index.tsx +1 -0
  227. package/src/plugins/builtin/ipo-calendar/index.tsx +1 -0
  228. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  229. package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
  230. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  231. package/src/plugins/builtin/market-movers/index.tsx +1 -0
  232. package/src/plugins/builtin/market-valuation/align.ts +122 -0
  233. package/src/plugins/builtin/market-valuation/cache.ts +32 -0
  234. package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
  235. package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
  236. package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
  237. package/src/plugins/builtin/market-valuation/client.ts +116 -0
  238. package/src/plugins/builtin/market-valuation/defs.ts +251 -0
  239. package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
  240. package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
  241. package/src/plugins/builtin/market-valuation/headless.ts +170 -0
  242. package/src/plugins/builtin/market-valuation/index.tsx +64 -0
  243. package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
  244. package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
  245. package/src/plugins/builtin/market-valuation/model.ts +8 -0
  246. package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
  247. package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
  248. package/src/plugins/builtin/market-valuation/series.ts +12 -0
  249. package/src/plugins/builtin/market-valuation/settings.ts +38 -0
  250. package/src/plugins/builtin/market-valuation/sources.ts +130 -0
  251. package/src/plugins/builtin/market-valuation/trend.ts +89 -0
  252. package/src/plugins/builtin/market-valuation/view.ts +137 -0
  253. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
  254. package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
  255. package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
  256. package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
  257. package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
  258. package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
  259. package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
  260. package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
  261. package/src/plugins/builtin/news/wire/index.tsx +31 -44
  262. package/src/plugins/builtin/options/analytics.test.ts +83 -0
  263. package/src/plugins/builtin/options/analytics.ts +110 -0
  264. package/src/plugins/builtin/options/index.tsx +18 -2
  265. package/src/plugins/builtin/options/table.ts +121 -51
  266. package/src/plugins/builtin/options/types.ts +22 -15
  267. package/src/plugins/builtin/options/view.test.tsx +53 -1
  268. package/src/plugins/builtin/options/view.tsx +92 -41
  269. package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
  270. package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
  271. package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
  272. package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
  273. package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
  274. package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
  275. package/src/plugins/builtin/plugin-module.test.ts +2 -4
  276. package/src/plugins/builtin/plugin-module.ts +9 -8
  277. package/src/plugins/builtin/portfolio-list/index.tsx +1 -0
  278. package/src/plugins/builtin/research/index.tsx +4 -0
  279. package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
  280. package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
  281. package/src/plugins/builtin/research-search/data.ts +109 -0
  282. package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
  283. package/src/plugins/builtin/research-search/document-view.tsx +254 -0
  284. package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
  285. package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
  286. package/src/plugins/builtin/research-search/index.tsx +85 -0
  287. package/src/plugins/builtin/research-search/model.test.ts +40 -0
  288. package/src/plugins/builtin/research-search/model.ts +291 -0
  289. package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
  290. package/src/plugins/builtin/research-search/pane.tsx +678 -0
  291. package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
  292. package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
  293. package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
  294. package/src/plugins/builtin/research-search/snippet.ts +134 -0
  295. package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
  296. package/src/plugins/builtin/scanner/flow-model.ts +29 -1
  297. package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
  298. package/src/plugins/builtin/scanner/index.ts +2 -0
  299. package/src/plugins/builtin/sec/index.tsx +1 -0
  300. package/src/plugins/builtin/sectors/index.tsx +1 -0
  301. package/src/plugins/builtin/shared/series-cache.ts +93 -0
  302. package/src/plugins/builtin/short-interest/index.tsx +1 -0
  303. package/src/plugins/builtin/short-interest/pane.tsx +1 -1
  304. package/src/plugins/builtin/thirteenf/index.tsx +1 -0
  305. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +3 -5
  306. package/src/plugins/builtin/ticker-detail/index.tsx +2 -14
  307. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
  308. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  309. package/src/plugins/builtin/volatility/index.tsx +1 -1
  310. package/src/plugins/builtin/world-indices/index.tsx +1 -0
  311. package/src/plugins/builtin/world-venue-map/index.ts +27 -0
  312. package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
  313. package/src/plugins/builtin/world-venue-map/map.tsx +481 -0
  314. package/src/plugins/builtin/world-venue-map/model.test.ts +85 -0
  315. package/src/plugins/builtin/world-venue-map/model.ts +268 -0
  316. package/src/plugins/builtin/world-venue-map/pane.tsx +300 -0
  317. package/src/plugins/builtin/world-venue-map/world-outlines.ts +2 -0
  318. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  319. package/src/plugins/bundle.test.ts +109 -0
  320. package/src/plugins/bundle.ts +139 -0
  321. package/src/plugins/catalog-backend.ts +6 -44
  322. package/src/plugins/catalog-browser.test.ts +1 -0
  323. package/src/plugins/catalog-browser.ts +12 -0
  324. package/src/plugins/catalog-manifest.test.ts +43 -0
  325. package/src/plugins/catalog-manifest.ts +92 -0
  326. package/src/plugins/catalog-ui.ts +20 -4
  327. package/src/plugins/catalog.ts +9 -2
  328. package/src/plugins/current-target.ts +28 -0
  329. package/src/plugins/host-contract.ts +37 -0
  330. package/src/plugins/host-link.ts +158 -0
  331. package/src/plugins/host-modules.ts +61 -0
  332. package/src/plugins/loader.ts +41 -22
  333. package/src/plugins/ownership.ts +1 -0
  334. package/src/plugins/prediction-markets/index.tsx +1 -0
  335. package/src/plugins/registry/context.ts +3 -0
  336. package/src/plugins/registry/contributions.ts +27 -0
  337. package/src/plugins/registry/index.test.ts +25 -0
  338. package/src/plugins/registry/index.ts +8 -0
  339. package/src/plugins/registry/pane-settings.test.ts +53 -0
  340. package/src/plugins/registry/pane-settings.ts +29 -3
  341. package/src/plugins/seed.test.ts +83 -0
  342. package/src/plugins/seed.ts +80 -0
  343. package/src/public/broker.ts +31 -0
  344. package/src/public/market-data.ts +9 -0
  345. package/src/public/pane-hooks.ts +57 -0
  346. package/src/public/public-api.test.ts +285 -0
  347. package/src/public/react.ts +62 -0
  348. package/src/public/test-support.ts +23 -0
  349. package/src/public/time-series.ts +8 -0
  350. package/src/public/utils.ts +77 -0
  351. package/src/remote/layout-helpers.ts +6 -8
  352. package/src/remote/resources.ts +2 -0
  353. package/src/remote/schema.ts +1 -0
  354. package/src/remote/semantic-tree.test.tsx +105 -0
  355. package/src/remote/semantic-tree.tsx +53 -35
  356. package/src/renderers/browser/main.tsx +6 -0
  357. package/src/renderers/browser/ui-host.tsx +11 -0
  358. package/src/renderers/cloudflare/worker.test.ts +19 -0
  359. package/src/renderers/cloudflare/worker.ts +1 -1
  360. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -2
  361. package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
  362. package/src/renderers/electrobun/bun/index.ts +6 -2
  363. package/src/renderers/electrobun/shared/protocol.ts +25 -0
  364. package/src/renderers/electrobun/view/build-assets.ts +0 -1
  365. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
  366. package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
  367. package/src/renderers/electrobun/view/external-plugins.ts +63 -0
  368. package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
  369. package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
  370. package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
  371. package/src/renderers/electrobun/view/host/mouse.ts +16 -2
  372. package/src/renderers/electrobun/view/main.tsx +27 -2
  373. package/src/renderers/electrobun/view/styles.css +5 -0
  374. package/src/renderers/electrobun/view/toast-host.tsx +18 -0
  375. package/src/renderers/electrobun/view/ui-host.tsx +3 -0
  376. package/src/renderers/opentui/chart-surface.tsx +5 -1
  377. package/src/renderers/opentui/host.tsx +20 -2
  378. package/src/renderers/opentui/interaction-performance.test.ts +79 -0
  379. package/src/renderers/opentui/interaction-performance.ts +188 -0
  380. package/src/renderers/opentui/start.tsx +26 -1
  381. package/src/renderers/opentui/test-utils.tsx +13 -0
  382. package/src/renderers/opentui/toast-host.tsx +26 -2
  383. package/src/renderers/opentui/ui-host.tsx +1 -0
  384. package/src/sources/provider-router/search.test.ts +191 -0
  385. package/src/sources/provider-router/search.ts +92 -39
  386. package/src/state/app/context/index.tsx +2 -0
  387. package/src/state/app/context/selector.test.tsx +33 -1
  388. package/src/state/hooks/quote-streaming.test.tsx +93 -0
  389. package/src/state/hooks/quote-streaming.ts +106 -30
  390. package/src/state/pane-table-export-registry.ts +50 -0
  391. package/src/theme/color-utils.ts +1 -1
  392. package/src/theme/colors.ts +50 -0
  393. package/src/theme/themes.test.ts +15 -2
  394. package/src/theme/themes.ts +19 -1
  395. package/src/tickers/search/index.test.ts +26 -0
  396. package/src/tickers/search/index.ts +42 -17
  397. package/src/tickers/search/ranking.ts +14 -0
  398. package/src/time-series/chart-data.test.ts +216 -0
  399. package/src/time-series/range.ts +12 -0
  400. package/src/time-series/resolution.test.ts +25 -26
  401. package/src/time-series/resolution.ts +44 -25
  402. package/src/time-series/resolve.ts +7 -0
  403. package/src/time-series/spec.ts +5 -5
  404. package/src/time-series/types.ts +3 -1
  405. package/src/time-series/use-chart-resolution.ts +5 -0
  406. package/src/types/config.ts +123 -3
  407. package/src/types/data-provider.ts +11 -0
  408. package/src/types/headless.ts +161 -0
  409. package/src/types/plugin.ts +104 -20
  410. package/src/ui/host.tsx +19 -1
  411. package/src/ui/index.tsx +1 -0
  412. package/src/ui/toast.tsx +8 -4
  413. package/src/utils/csv.test.ts +13 -0
  414. package/src/utils/csv.ts +37 -0
  415. package/src/utils/format.ts +35 -0
  416. package/src/utils/fuzzy-search.test.ts +94 -0
  417. package/src/utils/fuzzy-search.ts +81 -22
  418. package/src/utils/save-text-file.test.ts +24 -0
  419. package/src/utils/save-text-file.ts +36 -0
  420. package/src/utils/shortcut-labels.ts +14 -0
  421. package/src/components/chart/core/axis-format.ts +0 -157
  422. package/src/components/chart/core/index.test.ts +0 -1075
  423. package/src/components/chart/core/projection.ts +0 -357
  424. package/src/components/chart/core/render-utils.ts +0 -4
  425. package/src/components/chart/core/renderer.ts +0 -244
  426. package/src/components/chart/core/scene.ts +0 -180
  427. package/src/components/chart/core/time-axis.ts +0 -330
  428. package/src/components/chart/cursor-motion.ts +0 -47
  429. package/src/components/chart/indicators/types.ts +0 -26
  430. package/src/components/chart/market-session.ts +0 -176
  431. package/src/components/chart/multi-line/renderer.test.ts +0 -83
  432. package/src/components/chart/multi-line/renderer.ts +0 -161
  433. package/src/components/chart/multi-line/scene.ts +0 -188
  434. package/src/components/chart/native/raster/layout.ts +0 -129
  435. package/src/components/chart/native/raster/price-chart.ts +0 -244
  436. package/src/components/chart/rendering/chart-draw.ts +0 -270
  437. package/src/components/chart/rendering/geometry.ts +0 -95
  438. package/src/components/chart/rendering/pixel-buffer.ts +0 -267
  439. package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
  440. package/src/components/chart/scatter-chart-renderer.ts +0 -223
  441. package/src/components/chart/static/chart/surface.tsx +0 -358
  442. package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
  443. package/src/components/command-bar/routes/root/article-results.ts +0 -55
  444. package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
  445. package/src/plugins/builtin/news/wire/article-search.ts +0 -140
  446. package/src/plugins/builtin/substack/api/auth.ts +0 -185
  447. package/src/plugins/builtin/substack/api/cache.ts +0 -82
  448. package/src/plugins/builtin/substack/api/loaders.ts +0 -170
  449. package/src/plugins/builtin/substack/api/store.ts +0 -186
  450. package/src/plugins/builtin/substack/api/types.ts +0 -42
  451. package/src/plugins/builtin/substack/api.test.ts +0 -298
  452. package/src/plugins/builtin/substack/article-detail.tsx +0 -397
  453. package/src/plugins/builtin/substack/article-stack.tsx +0 -133
  454. package/src/plugins/builtin/substack/content.ts +0 -478
  455. package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
  456. package/src/plugins/builtin/substack/index.tsx +0 -49
  457. package/src/plugins/builtin/substack/login-view.tsx +0 -126
  458. package/src/plugins/builtin/substack/model.test.ts +0 -155
  459. package/src/plugins/builtin/substack/normalize.ts +0 -343
  460. package/src/plugins/builtin/substack/pane-footer.ts +0 -52
  461. package/src/plugins/builtin/substack/pane-state.ts +0 -170
  462. package/src/plugins/builtin/substack/pane.tsx +0 -547
  463. package/src/plugins/builtin/substack/read-state.ts +0 -30
  464. package/src/plugins/builtin/substack/table.ts +0 -111
  465. package/src/plugins/builtin/substack/types.ts +0 -71
  466. package/src/plugins/builtin/substack/utils.ts +0 -131
  467. package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
  468. package/src/plugins/ibkr/account-cache.test.ts +0 -102
  469. package/src/plugins/ibkr/account-cache.ts +0 -24
  470. package/src/plugins/ibkr/broker-adapter.ts +0 -286
  471. package/src/plugins/ibkr/config.test.ts +0 -79
  472. package/src/plugins/ibkr/config.ts +0 -250
  473. package/src/plugins/ibkr/dialogs.tsx +0 -40
  474. package/src/plugins/ibkr/flex/index.test.ts +0 -264
  475. package/src/plugins/ibkr/flex/index.ts +0 -367
  476. package/src/plugins/ibkr/flex/statement-client.ts +0 -235
  477. package/src/plugins/ibkr/fundamental-parser.ts +0 -149
  478. package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
  479. package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
  480. package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
  481. package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
  482. package/src/plugins/ibkr/gateway/connection.ts +0 -152
  483. package/src/plugins/ibkr/gateway/contracts.ts +0 -132
  484. package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
  485. package/src/plugins/ibkr/gateway/helpers.ts +0 -33
  486. package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
  487. package/src/plugins/ibkr/gateway/history.ts +0 -120
  488. package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
  489. package/src/plugins/ibkr/gateway/market-data.ts +0 -345
  490. package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
  491. package/src/plugins/ibkr/gateway/orders.ts +0 -63
  492. package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
  493. package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
  494. package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
  495. package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
  496. package/src/plugins/ibkr/gateway/selection.ts +0 -51
  497. package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
  498. package/src/plugins/ibkr/gateway/service/index.ts +0 -429
  499. package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
  500. package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
  501. package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
  502. package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
  503. package/src/plugins/ibkr/gateway/service/native.ts +0 -543
  504. package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
  505. package/src/plugins/ibkr/gateway/types.ts +0 -27
  506. package/src/plugins/ibkr/index.test.tsx +0 -162
  507. package/src/plugins/ibkr/index.tsx +0 -159
  508. package/src/plugins/ibkr/instance-selection.test.ts +0 -120
  509. package/src/plugins/ibkr/instance-selection.ts +0 -36
  510. package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
  511. package/src/plugins/ibkr/portfolio-performance.ts +0 -129
  512. package/src/plugins/ibkr/trade/badge.tsx +0 -28
  513. package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
  514. package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
  515. package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
  516. package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
  517. package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
  518. package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
  519. package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
  520. package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
  521. package/src/plugins/ibkr/trade/tab/model.ts +0 -159
  522. package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
  523. package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
  524. package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
  525. package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
  526. package/src/plugins/ibkr/trade/utils.test.ts +0 -175
  527. package/src/plugins/ibkr/trade/utils.ts +0 -144
  528. package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
  529. package/src/plugins/ibkr/trading/pane.tsx +0 -332
  530. package/src/plugins/ibkr/trading/state.test.ts +0 -109
  531. package/src/plugins/ibkr/trading/state.ts +0 -335
@@ -0,0 +1,57 @@
1
+ import type { StatPoint } from "./transform";
2
+
3
+ const MS_PER_DAY = 86_400_000;
4
+
5
+ export interface TrendFit {
6
+ alpha: number;
7
+ beta: number;
8
+ sigma: number;
9
+ originMs: number;
10
+ }
11
+
12
+ /**
13
+ * Plain least squares against time. These series go negative routinely, so unlike
14
+ * the valuation ratios there is no log variant to choose.
15
+ */
16
+ export function fitTrend(points: readonly StatPoint[]): TrendFit {
17
+ const usable = points.filter((point) => Number.isFinite(point.value));
18
+ const empty: TrendFit = { alpha: 0, beta: 0, sigma: 0, originMs: 0 };
19
+ if (usable.length === 0) return empty;
20
+
21
+ const originMs = Date.parse(usable[0]!.date);
22
+ if (usable.length < 2) return { alpha: usable[0]!.value, beta: 0, sigma: 0, originMs };
23
+
24
+ const xs = usable.map((point) => (Date.parse(point.date) - originMs) / MS_PER_DAY);
25
+ const ys = usable.map((point) => point.value);
26
+ const n = xs.length;
27
+ let sumX = 0;
28
+ let sumY = 0;
29
+ let sumXX = 0;
30
+ let sumXY = 0;
31
+ for (let i = 0; i < n; i += 1) {
32
+ sumX += xs[i]!;
33
+ sumY += ys[i]!;
34
+ sumXX += xs[i]! * xs[i]!;
35
+ sumXY += xs[i]! * ys[i]!;
36
+ }
37
+ const denom = n * sumXX - sumX * sumX;
38
+ const beta = denom === 0 ? 0 : (n * sumXY - sumX * sumY) / denom;
39
+ const alpha = (sumY - beta * sumX) / n;
40
+ if (n < 3) return { alpha, beta, sigma: 0, originMs };
41
+
42
+ let residualSq = 0;
43
+ for (let i = 0; i < n; i += 1) {
44
+ const residual = ys[i]! - (alpha + beta * xs[i]!);
45
+ residualSq += residual * residual;
46
+ }
47
+ return { alpha, beta, sigma: Math.sqrt(residualSq / (n - 2)), originMs };
48
+ }
49
+
50
+ export function trendAt(fit: TrendFit, date: string): number {
51
+ return fit.alpha + fit.beta * ((Date.parse(date) - fit.originMs) / MS_PER_DAY);
52
+ }
53
+
54
+ export function sigmaVsTrend(fit: TrendFit, value: number, date: string): number {
55
+ if (!(fit.sigma > 0)) return 0;
56
+ return (value - trendAt(fit, date)) / fit.sigma;
57
+ }
@@ -0,0 +1,90 @@
1
+ import type { StatBuild } from "./client";
2
+ import type { StatDef } from "./defs";
3
+ import { periodsPerYear, type StatPoint } from "./transform";
4
+ import { sigmaVsTrend, trendAt } from "./trend";
5
+
6
+ export type StatRangeId = "5Y" | "20Y" | "ALL";
7
+
8
+ const MS_PER_YEAR = 365.25 * 24 * 60 * 60 * 1000;
9
+
10
+ export const STAT_RANGE_WINDOWS_MS: { readonly [K in StatRangeId]: number | null } = {
11
+ "5Y": 5 * MS_PER_YEAR,
12
+ "20Y": 20 * MS_PER_YEAR,
13
+ ALL: null,
14
+ };
15
+
16
+ export interface StatViewModel {
17
+ stat: StatDef;
18
+ range: StatRangeId;
19
+ latest: StatPoint;
20
+ /** The print before this one, for the direction of the last move. */
21
+ previous: StatPoint | null;
22
+ yearAgo: StatPoint | null;
23
+ changeOnPrevious: number | null;
24
+ /** Where the current reading sits in the series' own history. */
25
+ percentile: number;
26
+ sigmaVsTrend: number;
27
+ mean: number;
28
+ high: StatPoint;
29
+ low: StatPoint;
30
+ visible: StatPoint[];
31
+ observationStale: boolean;
32
+ }
33
+
34
+ export function sliceByRange(
35
+ points: readonly StatPoint[],
36
+ range: StatRangeId,
37
+ ): StatPoint[] {
38
+ const window = STAT_RANGE_WINDOWS_MS[range];
39
+ if (window == null || points.length === 0) return [...points];
40
+ const cutoff = Date.parse(points.at(-1)!.date) - window;
41
+ const sliced = points.filter((point) => Date.parse(point.date) >= cutoff);
42
+ return sliced.length >= 2 ? sliced : [...points];
43
+ }
44
+
45
+ function extreme(points: readonly StatPoint[], pick: "high" | "low"): StatPoint {
46
+ let best = points[0]!;
47
+ for (const point of points) {
48
+ if (pick === "high" ? point.value > best.value : point.value < best.value) best = point;
49
+ }
50
+ return best;
51
+ }
52
+
53
+ export function projectStat(
54
+ build: StatBuild,
55
+ range: StatRangeId,
56
+ opts: { nowMs?: number } = {},
57
+ ): StatViewModel {
58
+ const { stat, points, trend } = build;
59
+ const latest = points[points.length - 1]!;
60
+ const nowMs = opts.nowMs ?? Date.now();
61
+ const perYear = periodsPerYear(points.map((point) => ({ date: point.date, value: point.value })));
62
+ const yearAgo = points[points.length - 1 - perYear] ?? null;
63
+ const previous = points[points.length - 2] ?? null;
64
+ const atOrBelow = points.filter((point) => point.value <= latest.value).length;
65
+
66
+ return {
67
+ stat,
68
+ range,
69
+ latest,
70
+ previous,
71
+ yearAgo,
72
+ changeOnPrevious: previous ? latest.value - previous.value : null,
73
+ percentile: points.length === 0 ? 0 : (100 * atOrBelow) / points.length,
74
+ sigmaVsTrend: sigmaVsTrend(trend, latest.value, latest.date),
75
+ mean: points.reduce((total, point) => total + point.value, 0) / points.length,
76
+ high: extreme(points, "high"),
77
+ low: extreme(points, "low"),
78
+ visible: sliceByRange(points, range),
79
+ observationStale: nowMs - Date.parse(latest.date) > stat.staleAfterMs,
80
+ };
81
+ }
82
+
83
+ export function selectStatViews(
84
+ builds: readonly StatBuild[],
85
+ range: StatRangeId,
86
+ ): StatViewModel[] {
87
+ return builds.map((build) => projectStat(build, range));
88
+ }
89
+
90
+ export { trendAt };
@@ -1,9 +1,8 @@
1
1
  import { useMemo } from "react";
2
2
  import { Box, Text, TextAttributes, useUiHost } from "../../../ui";
3
- import { StaticChartSurface } from "../../../components";
3
+ import { StaticChartSurface, type StaticChartOverlay } from "../../../components/chart/static";
4
4
  import { colors, blendHex } from "../../../theme/colors";
5
- import { resolveChartPalette } from "../../../components/chart/core/renderer";
6
- import type { ChartIndicatorOverlays } from "../../../components/chart/core/types";
5
+ import { resolveChartPalette } from "../../../components/chart/core/palette";
7
6
  import type {
8
7
  FearGreedData,
9
8
  FearGreedIndicator,
@@ -82,19 +81,9 @@ export function PreviousScoreGrid({ data, width, layout = "grid" }: { data: Fear
82
81
  );
83
82
  }
84
83
 
85
- function chartOverlay(indicator: FearGreedIndicator): ChartIndicatorOverlays | null {
86
- if (indicator.secondaryPoints.length === 0) return null;
87
- return {
88
- smaLines: [{
89
- period: 0,
90
- points: indicator.secondaryPoints,
91
- color: colors.warning,
92
- }],
93
- emaLines: [],
94
- bollinger: null,
95
- rsi: null,
96
- macd: null,
97
- };
84
+ function chartOverlay(indicator: FearGreedIndicator): StaticChartOverlay[] | undefined {
85
+ if (indicator.secondaryPoints.length === 0) return undefined;
86
+ return [{ id: "secondary", color: colors.warning, points: indicator.secondaryPoints }];
98
87
  }
99
88
 
100
89
  function SentimentChart({
@@ -120,7 +109,7 @@ function SentimentChart({
120
109
  primaryLabel: string;
121
110
  secondaryLabel?: string;
122
111
  secondaryValue?: number | null;
123
- overlays?: ChartIndicatorOverlays | null;
112
+ overlays?: StaticChartOverlay[];
124
113
  }) {
125
114
  const isDesktopWeb = useUiHost().kind === "desktop-web";
126
115
  const stackMeta = width < CHART_META_STACK_WIDTH;
@@ -183,7 +172,7 @@ function SentimentChart({
183
172
  height={chartHeight}
184
173
  mode="line"
185
174
  colors={palette}
186
- indicators={overlays}
175
+ overlays={overlays}
187
176
  showTimeAxis
188
177
  timeAxisColor={colors.textDim}
189
178
  yAxisColor={colors.textDim}
@@ -1,5 +1,4 @@
1
1
  import type { ProjectedChartPoint } from "../../../components/chart/core/data";
2
- import type { OverlayPoint } from "../../../components/chart/indicators/types";
3
2
 
4
3
  const CNN_FEAR_GREED_GRAPH_URL = "https://production.dataviz.cnn.io/index/fearandgreed/graphdata";
5
4
  const CNN_REFERER = "https://www.cnn.com/markets/fear-and-greed";
@@ -69,6 +68,12 @@ interface FearGreedIndicatorDefinition {
69
68
  valueFormat: FearGreedValueFormat;
70
69
  }
71
70
 
71
+ /** A secondary reading aligned to the primary series by observation index. */
72
+ interface OverlayPoint {
73
+ index: number;
74
+ value: number;
75
+ }
76
+
72
77
  export interface FearGreedIndicator {
73
78
  definition: FearGreedIndicatorDefinition;
74
79
  score: number | null;
@@ -250,6 +250,7 @@ export const futuresModule: PluginModule = {
250
250
  defaultPosition: "right",
251
251
  defaultMode: "floating",
252
252
  defaultFloatingSize: { width: 76, height: 34 },
253
+ tableExport: true,
253
254
  // Resolved per open so the dialog shows the full default set until the
254
255
  // user saves a narrower selection.
255
256
  settings: (context) => ({
@@ -169,6 +169,7 @@ export const fxMatrixModule: PluginModule = {
169
169
  defaultPosition: "right",
170
170
  defaultMode: "floating",
171
171
  defaultFloatingSize: { width: 105, height: 14 },
172
+ tableExport: true,
172
173
  settings: (context) => ({
173
174
  title: "FX Cross Rates Settings",
174
175
  values: {
@@ -239,6 +239,10 @@ function HelpPane({ focused, width, height }: PaneProps) {
239
239
  description="Copy a screenshot of the focused pane."
240
240
  />
241
241
  )}
242
+ <ShortcutRow
243
+ badges={[platformShortcut(["Shift", "E"])]}
244
+ description="Export the focused pane's table as CSV."
245
+ />
242
246
  <ShortcutRow
243
247
  badges={[platformShortcut(["Shift", "L"])]}
244
248
  description="Open layout actions."
@@ -22,6 +22,7 @@ export const holdersModule: PluginModule = {
22
22
  defaultPosition: "right",
23
23
  defaultMode: "floating",
24
24
  defaultFloatingSize: { width: 105, height: 34 },
25
+ tableExport: true,
25
26
  },
26
27
  ],
27
28
 
@@ -266,6 +266,7 @@ export const insiderModule: PluginModule = {
266
266
  defaultPosition: "right",
267
267
  defaultMode: "floating",
268
268
  defaultFloatingSize: { width: 100, height: 30 },
269
+ tableExport: true,
269
270
  },
270
271
  ],
271
272
 
@@ -40,6 +40,7 @@ export const ipoCalendarModule: PluginModule = {
40
40
  defaultPosition: "right",
41
41
  defaultMode: "floating",
42
42
  defaultFloatingSize: { width: 110, height: 28 },
43
+ tableExport: true,
43
44
  },
44
45
  ],
45
46
 
@@ -54,7 +54,7 @@ import {
54
54
  buildModeFields,
55
55
  type InlineField,
56
56
  } from "./fields";
57
- import type { StaticChartXMarker } from "../../../components/chart/static/chart/surface";
57
+ import type { StaticChartXMarker } from "../../../components/chart/static";
58
58
  import {
59
59
  KellyCurveSection,
60
60
  KellyResultMetrics,
@@ -1,7 +1,7 @@
1
1
  import { Box, Text, TextAttributes } from "../../../ui";
2
2
  import { StaticChartSurface } from "../../../components";
3
- import { resolveChartPalette } from "../../../components/chart/core/renderer";
4
- import type { StaticChartXMarker } from "../../../components/chart/static/chart/surface";
3
+ import { resolveChartPalette } from "../../../components/chart/core/palette";
4
+ import type { StaticChartXMarker } from "../../../components/chart/static";
5
5
  import { colors, priceColor } from "../../../theme/colors";
6
6
  import { formatCompact, formatCurrency, formatNumber } from "../../../utils/format";
7
7
  import type { ProjectedChartPoint } from "../../../components/chart/core/data";
@@ -97,7 +97,6 @@ export function KellyCurveSection({
97
97
  width={Math.max(10, width - 2)}
98
98
  height={height}
99
99
  mode="line"
100
- axisMode="percent"
101
100
  colors={resolveChartPalette(colors, "positive")}
102
101
  yAxisLabel="Expected log growth"
103
102
  yAxisColor={colors.textDim}
@@ -12,6 +12,7 @@ export const marketHaltsModule: PluginModule = {
12
12
  defaultPosition: "right",
13
13
  defaultMode: "floating",
14
14
  defaultFloatingSize: { width: 124, height: 26 },
15
+ tableExport: true,
15
16
  },
16
17
  ],
17
18
 
@@ -324,6 +324,7 @@ export const marketMoversModule: PluginModule = {
324
324
  defaultPosition: "right",
325
325
  defaultMode: "floating",
326
326
  defaultFloatingSize: { width: 100, height: 36 },
327
+ tableExport: true,
327
328
  quickSettings: [LIVE_STREAMING_QUICK_SETTING],
328
329
  settings: (context) => withLiveStreamingSetting({
329
330
  title: "Market Movers Settings",
@@ -0,0 +1,122 @@
1
+ import type { IndicatorDef, SeriesDef } from "./defs";
2
+ import type { DatedSeries } from "./series";
3
+
4
+ export interface ScaledObs {
5
+ date: string;
6
+ value: number;
7
+ }
8
+
9
+ export interface RatioPoint {
10
+ date: string;
11
+ ratio: number;
12
+ /** Present only when both legs are dollar amounts worth showing. */
13
+ numeratorBillions?: number;
14
+ denominatorBillions?: number;
15
+ }
16
+
17
+ export interface ValuationSeries {
18
+ indicatorId: string;
19
+ points: RatioPoint[];
20
+ /** Observation date of the slowest leg, which usually lags the headline value. */
21
+ vintageDate: string;
22
+ }
23
+
24
+ function parseDateMs(date: string): number {
25
+ return Date.parse(date);
26
+ }
27
+
28
+ /** "2026Q1" style label for the low-frequency leg behind a faster-moving value. */
29
+ export function vintageLabel(prefix: string, vintageDate: string): string {
30
+ const d = new Date(parseDateMs(vintageDate));
31
+ const quarter = Math.floor(d.getUTCMonth() / 3) + 1;
32
+ return `${prefix} as of ${d.getUTCFullYear()}Q${quarter}`;
33
+ }
34
+
35
+ export function scaleObservations(def: SeriesDef, data: DatedSeries): ScaledObs[] {
36
+ const points: ScaledObs[] = [];
37
+ for (const obs of data.observations) {
38
+ if (obs.value == null || !Number.isFinite(obs.value)) continue;
39
+ points.push({ date: obs.date, value: obs.value * def.scaleToBillions });
40
+ }
41
+ points.sort((a, b) => a.date.localeCompare(b.date));
42
+ return points;
43
+ }
44
+
45
+ /**
46
+ * Carries a low-frequency denominator across the numerator's dates, interpolating
47
+ * between prints and holding the last one flat past the final release.
48
+ */
49
+ export function alignToDenominator(
50
+ indicator: IndicatorDef,
51
+ numerator: readonly ScaledObs[],
52
+ denominator: readonly ScaledObs[],
53
+ withLevels: boolean,
54
+ ): RatioPoint[] {
55
+ if (denominator.length === 0 || numerator.length === 0) return [];
56
+ const firstMs = parseDateMs(denominator[0]!.date);
57
+ const last = denominator[denominator.length - 1]!;
58
+ const lastMs = parseDateMs(last.date);
59
+ const out: RatioPoint[] = [];
60
+
61
+ for (const point of numerator) {
62
+ const t = parseDateMs(point.date);
63
+ if (t < firstMs) continue;
64
+
65
+ let value: number;
66
+ if (t >= lastMs) {
67
+ value = last.value;
68
+ } else {
69
+ let i = 0;
70
+ while (i + 1 < denominator.length && parseDateMs(denominator[i + 1]!.date) <= t) i += 1;
71
+ const left = denominator[i]!;
72
+ const right = denominator[i + 1];
73
+ if (!right || parseDateMs(left.date) === t) {
74
+ value = left.value;
75
+ } else {
76
+ const t0 = parseDateMs(left.date);
77
+ const t1 = parseDateMs(right.date);
78
+ value = left.value + ((t - t0) / (t1 - t0)) * (right.value - left.value);
79
+ }
80
+ }
81
+ if (!(value > 0)) continue;
82
+ out.push({
83
+ date: point.date,
84
+ ratio: (point.value / value) * indicator.ratioScale,
85
+ ...(withLevels
86
+ ? { numeratorBillions: point.value, denominatorBillions: value }
87
+ : {}),
88
+ });
89
+ }
90
+ return out;
91
+ }
92
+
93
+ export function buildValuationSeries(
94
+ indicator: IndicatorDef,
95
+ legs: ReadonlyMap<string, DatedSeries>,
96
+ ): ValuationSeries {
97
+ if (indicator.input.kind === "direct") {
98
+ const def = indicator.input.series;
99
+ const data = legs.get(def.key);
100
+ if (!data) throw new Error(`missing ${def.key}`);
101
+ const points = scaleObservations(def, data).map((obs) => ({
102
+ date: obs.date,
103
+ ratio: obs.value * indicator.ratioScale,
104
+ }));
105
+ if (points.length === 0) throw new Error("no observations");
106
+ return { indicatorId: indicator.id, points, vintageDate: points.at(-1)!.date };
107
+ }
108
+
109
+ const { numerator, denominator, levels } = indicator.input;
110
+ const top = legs.get(numerator.key);
111
+ const bottom = legs.get(denominator.key);
112
+ if (!top || !bottom) throw new Error(`missing ${!top ? numerator.key : denominator.key}`);
113
+ const scaledTop = scaleObservations(numerator, top);
114
+ const scaledBottom = scaleObservations(denominator, bottom);
115
+ const points = alignToDenominator(indicator, scaledTop, scaledBottom, levels != null);
116
+ if (points.length === 0) throw new Error("no overlapping observations");
117
+ return {
118
+ indicatorId: indicator.id,
119
+ points,
120
+ vintageDate: scaledBottom.at(-1)!.date,
121
+ };
122
+ }
@@ -0,0 +1,32 @@
1
+ import { createSeriesCache } from "../shared/series-cache";
2
+ import type { DatedObservation } from "./series";
3
+ import type { PluginPersistence } from "../../../types/plugin";
4
+
5
+ const cache = createSeriesCache("market-valuation-series", 6 * 60 * 60 * 1000);
6
+
7
+ export type { SeriesCacheEntry } from "../shared/series-cache";
8
+
9
+ export function attachValuationPersistence(next: PluginPersistence): void {
10
+ cache.attach(next);
11
+ }
12
+
13
+ export function resetValuationPersistence(): void {
14
+ cache.reset();
15
+ }
16
+
17
+ export function hydrateValuationSeries(
18
+ entries: readonly (readonly [string, DatedObservation[]])[],
19
+ ): void {
20
+ cache.hydrate(entries);
21
+ }
22
+
23
+ export function getCachedSeries(key: string, options?: { allowExpired?: boolean }) {
24
+ return cache.get(key, options);
25
+ }
26
+
27
+ export function loadCachedSeries(
28
+ key: string,
29
+ loader: () => Promise<DatedObservation[]>,
30
+ ): Promise<DatedObservation[]> {
31
+ return cache.load(key, loader);
32
+ }