gloomberb 0.2.0 → 0.3.1

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 (310) hide show
  1. package/README.md +20 -19
  2. package/bin/gloomberb +3 -0
  3. package/package.json +5 -4
  4. package/patches/@opentui%2Fcore@0.1.90.patch +356 -0
  5. package/src/app.tsx +1330 -0
  6. package/src/brokers/sync-broker-instance.test.ts +100 -0
  7. package/src/brokers/sync-broker-instance.ts +341 -0
  8. package/src/cli/commands/plugins.ts +173 -0
  9. package/src/cli/commands/portfolio.ts +210 -0
  10. package/src/cli/commands/search.ts +120 -0
  11. package/src/cli/commands/ticker.ts +375 -0
  12. package/src/cli/commands/watchlist.ts +210 -0
  13. package/src/cli/context.ts +62 -0
  14. package/src/cli/errors.ts +13 -0
  15. package/src/cli/helpers.ts +85 -0
  16. package/src/cli/index.ts +143 -0
  17. package/src/cli/ticker-resolution.ts +39 -0
  18. package/src/cli/types.ts +15 -0
  19. package/src/cli.test.ts +361 -0
  20. package/src/components/chart/chart-data.ts +239 -0
  21. package/src/components/chart/chart-renderer.ts +1199 -0
  22. package/src/components/chart/chart-types.ts +82 -0
  23. package/src/components/chart/chart-viewport.ts +21 -0
  24. package/src/components/chart/chart.test.ts +439 -0
  25. package/src/components/chart/comparison-chart-data.test.ts +109 -0
  26. package/src/components/chart/comparison-chart-data.ts +316 -0
  27. package/src/components/chart/comparison-chart-renderer.test.ts +84 -0
  28. package/src/components/chart/comparison-chart-renderer.ts +354 -0
  29. package/src/components/chart/comparison-stock-chart.tsx +1486 -0
  30. package/src/components/chart/cursor-motion.ts +48 -0
  31. package/src/components/chart/native/chart-rasterizer.ts +732 -0
  32. package/src/components/chart/native/kitty-adapter.ts +12 -0
  33. package/src/components/chart/native/kitty-manager.ts +142 -0
  34. package/src/components/chart/native/kitty-protocol.ts +110 -0
  35. package/src/components/chart/native/kitty-support.ts +71 -0
  36. package/src/components/chart/native/kitty.test.ts +620 -0
  37. package/src/components/chart/native/renderer-selection.ts +24 -0
  38. package/src/components/chart/native/surface-manager.ts +225 -0
  39. package/src/components/chart/native/surface-sync.ts +34 -0
  40. package/src/components/chart/stock-chart-renderer-switch.test.tsx +165 -0
  41. package/src/components/chart/stock-chart.test.ts +107 -0
  42. package/src/components/chart/stock-chart.tsx +1556 -0
  43. package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +137 -0
  44. package/src/components/command-bar/command-bar.test.tsx +1524 -0
  45. package/src/components/command-bar/command-bar.tsx +4823 -0
  46. package/src/components/command-bar/command-registry.ts +261 -0
  47. package/src/components/command-bar/helpers.test.ts +224 -0
  48. package/src/components/command-bar/helpers.ts +371 -0
  49. package/src/components/command-bar/root-shortcuts.ts +158 -0
  50. package/src/components/command-bar/view-model.test.ts +152 -0
  51. package/src/components/command-bar/view-model.ts +185 -0
  52. package/src/components/command-bar/workflow-ops.test.ts +70 -0
  53. package/src/components/command-bar/workflow-ops.ts +433 -0
  54. package/src/components/command-bar/workflow-types.ts +127 -0
  55. package/src/components/detail-feed-view.test.tsx +105 -0
  56. package/src/components/detail-feed-view.tsx +295 -0
  57. package/src/components/index.ts +32 -0
  58. package/src/components/layout/floating-pane.tsx +49 -0
  59. package/src/components/layout/header.tsx +129 -0
  60. package/src/components/layout/pane-header.tsx +44 -0
  61. package/src/components/layout/pane.tsx +49 -0
  62. package/src/components/layout/pixel-mouse-mode.test.ts +122 -0
  63. package/src/components/layout/pixel-mouse.test.ts +40 -0
  64. package/src/components/layout/shell.test.tsx +625 -0
  65. package/src/components/layout/shell.tsx +1200 -0
  66. package/src/components/layout/status-bar.test.tsx +173 -0
  67. package/src/components/layout/status-bar.tsx +138 -0
  68. package/src/components/markdown-editor.tsx +134 -0
  69. package/src/components/onboarding/onboarding-wizard.test.tsx +184 -0
  70. package/src/components/onboarding/onboarding-wizard.tsx +1365 -0
  71. package/src/components/pane-settings-dialog.tsx +468 -0
  72. package/src/components/pane-template-wizard.test.tsx +52 -0
  73. package/src/components/pane-template-wizard.tsx +199 -0
  74. package/src/components/price-selector-dialog.tsx +195 -0
  75. package/src/components/spinner.tsx +2 -0
  76. package/src/components/tab-bar.tsx +17 -0
  77. package/src/components/ticker-badge-text.test.tsx +160 -0
  78. package/src/components/ticker-badge-text.tsx +58 -0
  79. package/src/components/ticker-badge.tsx +88 -0
  80. package/src/components/ticker-list-table.tsx +188 -0
  81. package/src/components/toggle-list.tsx +74 -0
  82. package/src/components/ui/button.tsx +77 -0
  83. package/src/components/ui/data-table.tsx +210 -0
  84. package/src/components/ui/external-link.tsx +22 -0
  85. package/src/components/ui/fields.tsx +187 -0
  86. package/src/components/ui/frame.tsx +73 -0
  87. package/src/components/ui/index.ts +53 -0
  88. package/src/components/ui/list-view.tsx +166 -0
  89. package/src/components/ui/loading.tsx +70 -0
  90. package/src/components/ui/status.tsx +83 -0
  91. package/src/components/ui/tabs.tsx +47 -0
  92. package/src/components/ui/toggle.tsx +164 -0
  93. package/src/components/ui/ui.test.tsx +134 -0
  94. package/src/data/app-persistence.ts +25 -0
  95. package/src/data/config-store.test.ts +310 -0
  96. package/src/data/config-store.ts +469 -0
  97. package/src/data/plugin-state-store.ts +102 -0
  98. package/src/data/resource-store.ts +323 -0
  99. package/src/data/session-store.ts +52 -0
  100. package/src/data/sqlite-cache.test.ts +103 -0
  101. package/src/data/sqlite-database.ts +62 -0
  102. package/src/data/sqlite-json.ts +19 -0
  103. package/src/data/ticker-repository.ts +45 -0
  104. package/src/data/ticker-store.ts +46 -0
  105. package/src/index.tsx +67 -0
  106. package/src/market-data/coordinator.test.ts +369 -0
  107. package/src/market-data/coordinator.ts +580 -0
  108. package/src/market-data/hooks.tsx +234 -0
  109. package/src/market-data/query-store.ts +28 -0
  110. package/src/market-data/request-types.test.ts +64 -0
  111. package/src/market-data/request-types.ts +70 -0
  112. package/src/market-data/result-types.ts +56 -0
  113. package/src/market-data/selectors.ts +166 -0
  114. package/src/market-data/trace.ts +7 -0
  115. package/src/pane-settings.test.ts +71 -0
  116. package/src/pane-settings.ts +73 -0
  117. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +338 -0
  118. package/src/plugins/builtin/ai/gloomberb-cli.ts +70 -0
  119. package/src/plugins/builtin/ai/index.test.tsx +139 -0
  120. package/src/plugins/builtin/ai/index.tsx +86 -0
  121. package/src/plugins/builtin/ai/providers.ts +99 -0
  122. package/src/plugins/builtin/ai/runner.ts +82 -0
  123. package/src/plugins/builtin/ai/screener-contract.test.ts +117 -0
  124. package/src/plugins/builtin/ai/screener-contract.ts +174 -0
  125. package/src/plugins/builtin/ai/screener-pane.test.tsx +365 -0
  126. package/src/plugins/builtin/ai/screener-pane.tsx +1161 -0
  127. package/src/plugins/builtin/ai/settings.ts +79 -0
  128. package/src/plugins/builtin/ai/ticker-context.ts +64 -0
  129. package/src/plugins/builtin/ai/utils.ts +71 -0
  130. package/src/plugins/builtin/ask-ai.test.tsx +258 -0
  131. package/src/plugins/builtin/ask-ai.tsx +9 -0
  132. package/src/plugins/builtin/chat-controller.test.ts +217 -0
  133. package/src/plugins/builtin/chat-controller.ts +340 -0
  134. package/src/plugins/builtin/chat.test.tsx +451 -0
  135. package/src/plugins/builtin/chat.tsx +620 -0
  136. package/src/plugins/builtin/comparison-chart.test.tsx +277 -0
  137. package/src/plugins/builtin/comparison-chart.tsx +169 -0
  138. package/src/plugins/builtin/data-providers.ts +16 -0
  139. package/src/plugins/builtin/debug.tsx +351 -0
  140. package/src/plugins/builtin/help.test.tsx +110 -0
  141. package/src/plugins/builtin/help.tsx +281 -0
  142. package/src/plugins/builtin/layout-manager.tsx +264 -0
  143. package/src/plugins/builtin/manual-entry.tsx +25 -0
  144. package/src/plugins/builtin/news.tsx +143 -0
  145. package/src/plugins/builtin/notes-files.ts +58 -0
  146. package/src/plugins/builtin/notes.tsx +396 -0
  147. package/src/plugins/builtin/options-availability.test.tsx +179 -0
  148. package/src/plugins/builtin/options-availability.ts +158 -0
  149. package/src/plugins/builtin/options.tsx +364 -0
  150. package/src/plugins/builtin/portfolio-list/header.tsx +227 -0
  151. package/src/plugins/builtin/portfolio-list/index.tsx +99 -0
  152. package/src/plugins/builtin/portfolio-list/metrics.ts +436 -0
  153. package/src/plugins/builtin/portfolio-list/pane.tsx +533 -0
  154. package/src/plugins/builtin/portfolio-list/settings.ts +280 -0
  155. package/src/plugins/builtin/portfolio-list/summary.tsx +270 -0
  156. package/src/plugins/builtin/portfolio-list/table.tsx +64 -0
  157. package/src/plugins/builtin/portfolio-list.test.ts +74 -0
  158. package/src/plugins/builtin/portfolio-list.test.tsx +1164 -0
  159. package/src/plugins/builtin/portfolio-metrics.test.ts +153 -0
  160. package/src/plugins/builtin/quote-monitor.test.tsx +114 -0
  161. package/src/plugins/builtin/sec.tsx +250 -0
  162. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +43 -0
  163. package/src/plugins/builtin/ticker-detail/financials-tab.tsx +390 -0
  164. package/src/plugins/builtin/ticker-detail/index.tsx +80 -0
  165. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +242 -0
  166. package/src/plugins/builtin/ticker-detail/pane.tsx +183 -0
  167. package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +83 -0
  168. package/src/plugins/builtin/ticker-detail/settings.ts +132 -0
  169. package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +193 -0
  170. package/src/plugins/builtin/ticker-detail.test.tsx +578 -0
  171. package/src/plugins/builtin/yahoo.ts +18 -0
  172. package/src/plugins/event-bus.ts +37 -0
  173. package/src/plugins/ibkr/__snapshots__/trade-tab.test.tsx.snap +35 -0
  174. package/src/plugins/ibkr/account-cache.test.ts +101 -0
  175. package/src/plugins/ibkr/account-cache.ts +137 -0
  176. package/src/plugins/ibkr/broker-adapter.ts +168 -0
  177. package/src/plugins/ibkr/config.test.ts +68 -0
  178. package/src/plugins/ibkr/config.ts +262 -0
  179. package/src/plugins/ibkr/dialogs.tsx +83 -0
  180. package/src/plugins/ibkr/flex.test.ts +107 -0
  181. package/src/plugins/ibkr/flex.ts +267 -0
  182. package/src/plugins/ibkr/fundamental-parser.ts +149 -0
  183. package/src/plugins/ibkr/gateway-helpers.ts +28 -0
  184. package/src/plugins/ibkr/gateway-selection.ts +51 -0
  185. package/src/plugins/ibkr/gateway-service.test.ts +450 -0
  186. package/src/plugins/ibkr/gateway-service.ts +2228 -0
  187. package/src/plugins/ibkr/index.test.tsx +183 -0
  188. package/src/plugins/ibkr/index.tsx +153 -0
  189. package/src/plugins/ibkr/instance-selection.test.ts +121 -0
  190. package/src/plugins/ibkr/instance-selection.ts +36 -0
  191. package/src/plugins/ibkr/price-normalization.test.ts +38 -0
  192. package/src/plugins/ibkr/price-normalization.ts +59 -0
  193. package/src/plugins/ibkr/trade-badge.tsx +27 -0
  194. package/src/plugins/ibkr/trade-tab.test.tsx +225 -0
  195. package/src/plugins/ibkr/trade-tab.tsx +1050 -0
  196. package/src/plugins/ibkr/trade-utils.test.ts +175 -0
  197. package/src/plugins/ibkr/trade-utils.ts +149 -0
  198. package/src/plugins/ibkr/trading-pane.tsx +438 -0
  199. package/src/plugins/ibkr/trading-state.test.ts +109 -0
  200. package/src/plugins/ibkr/trading-state.ts +339 -0
  201. package/src/plugins/loader.ts +71 -0
  202. package/src/plugins/pane-manager.test.ts +103 -0
  203. package/src/plugins/pane-manager.ts +974 -0
  204. package/src/plugins/plugin-persistence.ts +85 -0
  205. package/src/plugins/plugin-runtime.test.tsx +185 -0
  206. package/src/plugins/plugin-runtime.tsx +175 -0
  207. package/src/plugins/prediction-markets/cache.ts +114 -0
  208. package/src/plugins/prediction-markets/categories.ts +223 -0
  209. package/src/plugins/prediction-markets/chart.tsx +512 -0
  210. package/src/plugins/prediction-markets/columns.ts +133 -0
  211. package/src/plugins/prediction-markets/controller-data.ts +614 -0
  212. package/src/plugins/prediction-markets/controller.ts +725 -0
  213. package/src/plugins/prediction-markets/detail/book.tsx +118 -0
  214. package/src/plugins/prediction-markets/detail/outcomes.tsx +102 -0
  215. package/src/plugins/prediction-markets/detail/overview.tsx +73 -0
  216. package/src/plugins/prediction-markets/detail/pane.tsx +308 -0
  217. package/src/plugins/prediction-markets/detail/rules.tsx +16 -0
  218. package/src/plugins/prediction-markets/detail/shared.tsx +29 -0
  219. package/src/plugins/prediction-markets/detail/trades.tsx +30 -0
  220. package/src/plugins/prediction-markets/detail.test.tsx +47 -0
  221. package/src/plugins/prediction-markets/index.tsx +102 -0
  222. package/src/plugins/prediction-markets/keyboard.ts +64 -0
  223. package/src/plugins/prediction-markets/launch.test.ts +126 -0
  224. package/src/plugins/prediction-markets/launch.ts +240 -0
  225. package/src/plugins/prediction-markets/metrics.ts +311 -0
  226. package/src/plugins/prediction-markets/navigation.ts +90 -0
  227. package/src/plugins/prediction-markets/outcome-order.ts +19 -0
  228. package/src/plugins/prediction-markets/pane.test.tsx +425 -0
  229. package/src/plugins/prediction-markets/pane.tsx +294 -0
  230. package/src/plugins/prediction-markets/plugin.test.tsx +570 -0
  231. package/src/plugins/prediction-markets/rows.ts +229 -0
  232. package/src/plugins/prediction-markets/services/fetch.ts +97 -0
  233. package/src/plugins/prediction-markets/services/kalshi-adapter.ts +555 -0
  234. package/src/plugins/prediction-markets/services/polymarket-adapter.ts +660 -0
  235. package/src/plugins/prediction-markets/services/polymarket-ws.ts +108 -0
  236. package/src/plugins/prediction-markets/settings.ts +164 -0
  237. package/src/plugins/prediction-markets/status.ts +24 -0
  238. package/src/plugins/prediction-markets/table.tsx +84 -0
  239. package/src/plugins/prediction-markets/test-helpers.tsx +636 -0
  240. package/src/plugins/prediction-markets/types.ts +186 -0
  241. package/src/plugins/registry.ts +633 -0
  242. package/src/sources/exchange-rates.ts +18 -0
  243. package/src/sources/gloomberb-cloud.test.ts +199 -0
  244. package/src/sources/gloomberb-cloud.ts +326 -0
  245. package/src/sources/provider-errors.ts +19 -0
  246. package/src/sources/provider-router.test.ts +1476 -0
  247. package/src/sources/provider-router.ts +1405 -0
  248. package/src/sources/sec-edgar.test.ts +286 -0
  249. package/src/sources/sec-edgar.ts +526 -0
  250. package/src/sources/yahoo-finance.test.ts +14 -0
  251. package/src/sources/yahoo-finance.ts +1017 -0
  252. package/src/state/app-activity.test.ts +41 -0
  253. package/src/state/app-activity.ts +106 -0
  254. package/src/state/app-bootstrap.test.ts +471 -0
  255. package/src/state/app-bootstrap.ts +308 -0
  256. package/src/state/app-context.test.ts +406 -0
  257. package/src/state/app-context.test.tsx +132 -0
  258. package/src/state/app-context.tsx +969 -0
  259. package/src/state/selectors.ts +67 -0
  260. package/src/state/session-persistence.test.ts +128 -0
  261. package/src/state/session-persistence.ts +161 -0
  262. package/src/state/ticker-refresh-queue.test.ts +46 -0
  263. package/src/state/ticker-refresh-queue.ts +40 -0
  264. package/src/state/use-inline-tickers.ts +174 -0
  265. package/src/state/use-quote-streaming.test.ts +37 -0
  266. package/src/state/use-quote-streaming.test.tsx +70 -0
  267. package/src/state/use-quote-streaming.ts +80 -0
  268. package/src/state/use-session-snapshot.ts +84 -0
  269. package/src/test-support/data-provider.ts +22 -0
  270. package/src/theme/color-utils.ts +67 -0
  271. package/src/theme/colors.ts +128 -0
  272. package/src/theme/themes.test.ts +45 -0
  273. package/src/theme/themes.ts +491 -0
  274. package/src/types/broker.ts +105 -0
  275. package/src/types/config.ts +434 -0
  276. package/src/types/data-provider.ts +81 -0
  277. package/src/types/financials.ts +142 -0
  278. package/src/types/instrument.ts +29 -0
  279. package/src/types/persistence.ts +21 -0
  280. package/src/types/plugin.ts +354 -0
  281. package/src/types/ticker.ts +58 -0
  282. package/src/types/trading.ts +85 -0
  283. package/src/updater.test.ts +162 -0
  284. package/src/updater.ts +247 -0
  285. package/src/utils/api-client.ts +666 -0
  286. package/src/utils/ascii-chart.ts +172 -0
  287. package/src/utils/broker-instances.ts +47 -0
  288. package/src/utils/cli-output.ts +83 -0
  289. package/src/utils/currency-units.test.ts +49 -0
  290. package/src/utils/currency-units.ts +82 -0
  291. package/src/utils/debug-log.ts +133 -0
  292. package/src/utils/exchange-rate-map.ts +8 -0
  293. package/src/utils/format.ts +158 -0
  294. package/src/utils/fuzzy-search.ts +34 -0
  295. package/src/utils/market-status.ts +95 -0
  296. package/src/utils/options.ts +86 -0
  297. package/src/utils/price-history.ts +39 -0
  298. package/src/utils/quote-time.test.ts +22 -0
  299. package/src/utils/quote-time.ts +50 -0
  300. package/src/utils/sec.test.ts +55 -0
  301. package/src/utils/sec.ts +45 -0
  302. package/src/utils/ticker-list.test.ts +22 -0
  303. package/src/utils/ticker-list.ts +35 -0
  304. package/src/utils/ticker-metadata.ts +51 -0
  305. package/src/utils/ticker-search.test.ts +227 -0
  306. package/src/utils/ticker-search.ts +764 -0
  307. package/src/utils/ticker-tokenizer.test.ts +48 -0
  308. package/src/utils/ticker-tokenizer.ts +72 -0
  309. package/src/version.ts +1 -0
  310. package/install.mjs +0 -68
@@ -0,0 +1,491 @@
1
+ import { blendForContrast, blendForContrastOnSurfaces, blendHex, contrastRatio, higherContrast } from "./color-utils";
2
+
3
+ export interface Theme {
4
+ name: string;
5
+ description: string;
6
+
7
+ bg: string;
8
+ panel: string;
9
+ border: string;
10
+ borderFocused: string;
11
+
12
+ text: string;
13
+ textDim: string;
14
+ textBright: string;
15
+ textMuted: string;
16
+
17
+ positive: string;
18
+ negative: string;
19
+ neutral: string;
20
+
21
+ header: string;
22
+ headerText: string;
23
+
24
+ selected: string;
25
+ selectedText: string;
26
+
27
+ commandBg: string;
28
+ commandBorder: string;
29
+ }
30
+
31
+ function highestMinimumContrast(surfaces: readonly string[], candidates: readonly string[]): string {
32
+ return candidates.reduce((best, candidate) => {
33
+ const bestScore = Math.min(...surfaces.map((surface) => contrastRatio(best, surface)));
34
+ const candidateScore = Math.min(...surfaces.map((surface) => contrastRatio(candidate, surface)));
35
+ return candidateScore > bestScore ? candidate : best;
36
+ });
37
+ }
38
+
39
+ function normalizeTheme(theme: Theme): Theme {
40
+ const bodySurfaces = [theme.bg, theme.panel] as const;
41
+ const text = blendForContrastOnSurfaces(
42
+ theme.text,
43
+ bodySurfaces,
44
+ highestMinimumContrast(bodySurfaces, [theme.textBright, theme.headerText, "#f2f2f2"]),
45
+ 4.5,
46
+ );
47
+ const textDim = blendForContrastOnSurfaces(
48
+ theme.textDim,
49
+ bodySurfaces,
50
+ highestMinimumContrast(bodySurfaces, [text, theme.textBright, "#d0d7de"]),
51
+ 4.5,
52
+ );
53
+ const textMuted = blendForContrastOnSurfaces(
54
+ theme.textMuted,
55
+ bodySurfaces,
56
+ highestMinimumContrast(bodySurfaces, [textDim, text, "#c0c7d1"]),
57
+ 3.6,
58
+ );
59
+ const positive = blendForContrastOnSurfaces(
60
+ theme.positive,
61
+ bodySurfaces,
62
+ blendHex(theme.positive, theme.textBright, 0.5),
63
+ 3.6,
64
+ );
65
+ const negative = blendForContrastOnSurfaces(
66
+ theme.negative,
67
+ bodySurfaces,
68
+ blendHex(theme.negative, theme.textBright, 0.45),
69
+ 3.6,
70
+ );
71
+ const neutral = blendForContrastOnSurfaces(
72
+ theme.neutral,
73
+ bodySurfaces,
74
+ highestMinimumContrast(bodySurfaces, [textDim, text, "#c0c7d1"]),
75
+ 3.6,
76
+ );
77
+ const headerText = blendForContrast(
78
+ theme.headerText,
79
+ theme.header,
80
+ higherContrast(text, theme.textBright, theme.header),
81
+ 4.5,
82
+ );
83
+ const selectedText = blendForContrast(
84
+ theme.selectedText,
85
+ theme.selected,
86
+ higherContrast(text, theme.textBright, theme.selected),
87
+ 4.5,
88
+ );
89
+
90
+ return {
91
+ ...theme,
92
+ text,
93
+ textDim,
94
+ textMuted,
95
+ positive,
96
+ negative,
97
+ neutral,
98
+ headerText,
99
+ selectedText,
100
+ };
101
+ }
102
+
103
+ const rawThemes: Record<string, Theme> = {
104
+ amber: {
105
+ name: "Amber",
106
+ description: "Classic amber-on-black terminal",
107
+ bg: "#000000",
108
+ panel: "#0a0a14",
109
+ border: "#1a3a5c",
110
+ borderFocused: "#ff8800",
111
+ text: "#ff8800",
112
+ textDim: "#886622",
113
+ textBright: "#ffaa00",
114
+ textMuted: "#555555",
115
+ positive: "#00cc66",
116
+ negative: "#ff3333",
117
+ neutral: "#888888",
118
+ header: "#0044aa",
119
+ headerText: "#ffffff",
120
+ selected: "#1a3a5c",
121
+ selectedText: "#ffaa00",
122
+ commandBg: "#111122",
123
+ commandBorder: "#ff8800",
124
+ },
125
+
126
+ green: {
127
+ name: "Green Phosphor",
128
+ description: "Retro green CRT monitor",
129
+ bg: "#000000",
130
+ panel: "#001100",
131
+ border: "#004400",
132
+ borderFocused: "#00ff00",
133
+ text: "#00cc00",
134
+ textDim: "#006600",
135
+ textBright: "#00ff00",
136
+ textMuted: "#444444",
137
+ positive: "#00ff66",
138
+ negative: "#ff4444",
139
+ neutral: "#666666",
140
+ header: "#003300",
141
+ headerText: "#00ff00",
142
+ selected: "#003300",
143
+ selectedText: "#00ff00",
144
+ commandBg: "#001100",
145
+ commandBorder: "#00cc00",
146
+ },
147
+
148
+ cyan: {
149
+ name: "Cyan",
150
+ description: "Cool cyan-on-black terminal",
151
+ bg: "#000000",
152
+ panel: "#000a0a",
153
+ border: "#003333",
154
+ borderFocused: "#00dddd",
155
+ text: "#00bbbb",
156
+ textDim: "#006666",
157
+ textBright: "#00ffff",
158
+ textMuted: "#444444",
159
+ positive: "#00ff88",
160
+ negative: "#ff4444",
161
+ neutral: "#666666",
162
+ header: "#002222",
163
+ headerText: "#00ffff",
164
+ selected: "#002a2a",
165
+ selectedText: "#00ffff",
166
+ commandBg: "#000a0a",
167
+ commandBorder: "#00bbbb",
168
+ },
169
+
170
+ red: {
171
+ name: "Red Phosphor",
172
+ description: "Crimson red-on-black terminal",
173
+ bg: "#000000",
174
+ panel: "#0a0000",
175
+ border: "#330000",
176
+ borderFocused: "#ff2222",
177
+ text: "#cc2222",
178
+ textDim: "#661111",
179
+ textBright: "#ff4444",
180
+ textMuted: "#444444",
181
+ positive: "#44cc44",
182
+ negative: "#ff6666",
183
+ neutral: "#666666",
184
+ header: "#220000",
185
+ headerText: "#ff3333",
186
+ selected: "#2a0000",
187
+ selectedText: "#ff4444",
188
+ commandBg: "#0a0000",
189
+ commandBorder: "#cc2222",
190
+ },
191
+
192
+ blue: {
193
+ name: "Blue Phosphor",
194
+ description: "Electric blue-on-black terminal",
195
+ bg: "#000000",
196
+ panel: "#00000a",
197
+ border: "#000044",
198
+ borderFocused: "#4488ff",
199
+ text: "#3377ee",
200
+ textDim: "#1a3a77",
201
+ textBright: "#66aaff",
202
+ textMuted: "#444444",
203
+ positive: "#00cc66",
204
+ negative: "#ff4444",
205
+ neutral: "#666666",
206
+ header: "#000033",
207
+ headerText: "#4488ff",
208
+ selected: "#001144",
209
+ selectedText: "#66aaff",
210
+ commandBg: "#00000a",
211
+ commandBorder: "#3377ee",
212
+ },
213
+
214
+ purple: {
215
+ name: "Purple Phosphor",
216
+ description: "Violet purple-on-black terminal",
217
+ bg: "#000000",
218
+ panel: "#080008",
219
+ border: "#220033",
220
+ borderFocused: "#bb55ff",
221
+ text: "#9944dd",
222
+ textDim: "#552288",
223
+ textBright: "#cc77ff",
224
+ textMuted: "#444444",
225
+ positive: "#44dd66",
226
+ negative: "#ff4444",
227
+ neutral: "#666666",
228
+ header: "#1a0028",
229
+ headerText: "#bb55ff",
230
+ selected: "#220033",
231
+ selectedText: "#cc77ff",
232
+ commandBg: "#080008",
233
+ commandBorder: "#9944dd",
234
+ },
235
+
236
+ pink: {
237
+ name: "Hot Pink",
238
+ description: "Neon pink-on-black terminal",
239
+ bg: "#000000",
240
+ panel: "#0a0006",
241
+ border: "#33001a",
242
+ borderFocused: "#ff44aa",
243
+ text: "#dd3399",
244
+ textDim: "#771155",
245
+ textBright: "#ff66bb",
246
+ textMuted: "#444444",
247
+ positive: "#44dd66",
248
+ negative: "#ff5555",
249
+ neutral: "#666666",
250
+ header: "#22000f",
251
+ headerText: "#ff44aa",
252
+ selected: "#2a0018",
253
+ selectedText: "#ff66bb",
254
+ commandBg: "#0a0006",
255
+ commandBorder: "#dd3399",
256
+ },
257
+
258
+ white: {
259
+ name: "White Phosphor",
260
+ description: "Clean white-on-black terminal",
261
+ bg: "#000000",
262
+ panel: "#0a0a0a",
263
+ border: "#333333",
264
+ borderFocused: "#ffffff",
265
+ text: "#cccccc",
266
+ textDim: "#666666",
267
+ textBright: "#ffffff",
268
+ textMuted: "#444444",
269
+ positive: "#00cc66",
270
+ negative: "#ff3333",
271
+ neutral: "#888888",
272
+ header: "#1a1a1a",
273
+ headerText: "#ffffff",
274
+ selected: "#222222",
275
+ selectedText: "#ffffff",
276
+ commandBg: "#0a0a0a",
277
+ commandBorder: "#cccccc",
278
+ },
279
+
280
+ tokyo: {
281
+ name: "Tokyo Night",
282
+ description: "Cool blue-purple palette",
283
+ bg: "#1a1b26",
284
+ panel: "#16161e",
285
+ border: "#3b4261",
286
+ borderFocused: "#7aa2f7",
287
+ text: "#c0caf5",
288
+ textDim: "#565f89",
289
+ textBright: "#ffffff",
290
+ textMuted: "#444b6a",
291
+ positive: "#9ece6a",
292
+ negative: "#f7768e",
293
+ neutral: "#565f89",
294
+ header: "#24283b",
295
+ headerText: "#7aa2f7",
296
+ selected: "#283457",
297
+ selectedText: "#c0caf5",
298
+ commandBg: "#16161e",
299
+ commandBorder: "#7aa2f7",
300
+ },
301
+
302
+ solarized: {
303
+ name: "Solarized Dark",
304
+ description: "Ethan Schoonover's classic palette",
305
+ bg: "#002b36",
306
+ panel: "#073642",
307
+ border: "#586e75",
308
+ borderFocused: "#b58900",
309
+ text: "#839496",
310
+ textDim: "#586e75",
311
+ textBright: "#fdf6e3",
312
+ textMuted: "#657b83",
313
+ positive: "#859900",
314
+ negative: "#dc322f",
315
+ neutral: "#657b83",
316
+ header: "#073642",
317
+ headerText: "#268bd2",
318
+ selected: "#0a4a5c",
319
+ selectedText: "#b58900",
320
+ commandBg: "#002b36",
321
+ commandBorder: "#268bd2",
322
+ },
323
+
324
+ dracula: {
325
+ name: "Dracula",
326
+ description: "Popular dark theme with vivid colors",
327
+ bg: "#282a36",
328
+ panel: "#21222c",
329
+ border: "#44475a",
330
+ borderFocused: "#bd93f9",
331
+ text: "#f8f8f2",
332
+ textDim: "#6272a4",
333
+ textBright: "#ffffff",
334
+ textMuted: "#6272a4",
335
+ positive: "#50fa7b",
336
+ negative: "#ff5555",
337
+ neutral: "#6272a4",
338
+ header: "#44475a",
339
+ headerText: "#bd93f9",
340
+ selected: "#44475a",
341
+ selectedText: "#f8f8f2",
342
+ commandBg: "#21222c",
343
+ commandBorder: "#bd93f9",
344
+ },
345
+
346
+ nord: {
347
+ name: "Nord",
348
+ description: "Arctic, north-bluish palette",
349
+ bg: "#2e3440",
350
+ panel: "#3b4252",
351
+ border: "#4c566a",
352
+ borderFocused: "#88c0d0",
353
+ text: "#d8dee9",
354
+ textDim: "#4c566a",
355
+ textBright: "#eceff4",
356
+ textMuted: "#4c566a",
357
+ positive: "#a3be8c",
358
+ negative: "#bf616a",
359
+ neutral: "#4c566a",
360
+ header: "#3b4252",
361
+ headerText: "#88c0d0",
362
+ selected: "#4c566a",
363
+ selectedText: "#eceff4",
364
+ commandBg: "#2e3440",
365
+ commandBorder: "#88c0d0",
366
+ },
367
+
368
+ monokai: {
369
+ name: "Monokai",
370
+ description: "Warm, high-contrast classic",
371
+ bg: "#272822",
372
+ panel: "#1e1f1c",
373
+ border: "#49483e",
374
+ borderFocused: "#f92672",
375
+ text: "#f8f8f2",
376
+ textDim: "#75715e",
377
+ textBright: "#ffffff",
378
+ textMuted: "#75715e",
379
+ positive: "#a6e22e",
380
+ negative: "#f92672",
381
+ neutral: "#75715e",
382
+ header: "#49483e",
383
+ headerText: "#e6db74",
384
+ selected: "#49483e",
385
+ selectedText: "#f8f8f2",
386
+ commandBg: "#1e1f1c",
387
+ commandBorder: "#f92672",
388
+ },
389
+
390
+ catppuccin: {
391
+ name: "Catppuccin Mocha",
392
+ description: "Soothing pastel theme",
393
+ bg: "#1e1e2e",
394
+ panel: "#181825",
395
+ border: "#45475a",
396
+ borderFocused: "#cba6f7",
397
+ text: "#cdd6f4",
398
+ textDim: "#585b70",
399
+ textBright: "#ffffff",
400
+ textMuted: "#6c7086",
401
+ positive: "#a6e3a1",
402
+ negative: "#f38ba8",
403
+ neutral: "#6c7086",
404
+ header: "#313244",
405
+ headerText: "#cba6f7",
406
+ selected: "#3e3f56",
407
+ selectedText: "#cdd6f4",
408
+ commandBg: "#181825",
409
+ commandBorder: "#cba6f7",
410
+ },
411
+
412
+ gruvbox: {
413
+ name: "Gruvbox Dark",
414
+ description: "Retro earthy tones",
415
+ bg: "#282828",
416
+ panel: "#1d2021",
417
+ border: "#504945",
418
+ borderFocused: "#fe8019",
419
+ text: "#ebdbb2",
420
+ textDim: "#928374",
421
+ textBright: "#fbf1c7",
422
+ textMuted: "#665c54",
423
+ positive: "#b8bb26",
424
+ negative: "#fb4934",
425
+ neutral: "#928374",
426
+ header: "#3c3836",
427
+ headerText: "#fabd2f",
428
+ selected: "#3c3836",
429
+ selectedText: "#ebdbb2",
430
+ commandBg: "#1d2021",
431
+ commandBorder: "#fe8019",
432
+ },
433
+
434
+ rosepine: {
435
+ name: "Rose Pine",
436
+ description: "Muted, elegant dark theme",
437
+ bg: "#191724",
438
+ panel: "#1f1d2e",
439
+ border: "#403d52",
440
+ borderFocused: "#c4a7e7",
441
+ text: "#e0def4",
442
+ textDim: "#6e6a86",
443
+ textBright: "#ffffff",
444
+ textMuted: "#524f67",
445
+ positive: "#31748f",
446
+ negative: "#eb6f92",
447
+ neutral: "#6e6a86",
448
+ header: "#26233a",
449
+ headerText: "#c4a7e7",
450
+ selected: "#332f4a",
451
+ selectedText: "#e0def4",
452
+ commandBg: "#1f1d2e",
453
+ commandBorder: "#c4a7e7",
454
+ },
455
+
456
+ midnight: {
457
+ name: "Midnight Blue",
458
+ description: "",
459
+ bg: "#000022",
460
+ panel: "#000033",
461
+ border: "#003366",
462
+ borderFocused: "#ff6600",
463
+ text: "#ccddff",
464
+ textDim: "#6688bb",
465
+ textBright: "#ffffff",
466
+ textMuted: "#445577",
467
+ positive: "#00cc66",
468
+ negative: "#ff3333",
469
+ neutral: "#6688bb",
470
+ header: "#001144",
471
+ headerText: "#ff6600",
472
+ selected: "#002255",
473
+ selectedText: "#ffffff",
474
+ commandBg: "#000033",
475
+ commandBorder: "#ff6600",
476
+ },
477
+ };
478
+
479
+ export const themes: Record<string, Theme> = Object.fromEntries(
480
+ Object.entries(rawThemes).map(([id, theme]) => [id, normalizeTheme(theme)]),
481
+ ) as Record<string, Theme>;
482
+
483
+ export const DEFAULT_THEME = "amber";
484
+
485
+ export function getThemeIds(): string[] {
486
+ return Object.keys(themes);
487
+ }
488
+
489
+ export function getTheme(id: string): Theme {
490
+ return themes[id] ?? themes[DEFAULT_THEME]!;
491
+ }
@@ -0,0 +1,105 @@
1
+ import type { Quote, TickerFinancials, PricePoint, OptionsChain } from "./financials";
2
+ import type { TimeRange } from "../components/chart/chart-types";
3
+ import type { BrokerInstanceConfig } from "./config";
4
+ import type { QuoteSubscriptionTarget } from "./data-provider";
5
+ import type { BrokerContractRef, InstrumentSearchResult } from "./instrument";
6
+ import type { BrokerAccount, BrokerExecution, BrokerOrder, BrokerOrderPreview, BrokerOrderRequest } from "./trading";
7
+ import type { CachePolicyMap } from "./persistence";
8
+
9
+ export interface BrokerPosition {
10
+ ticker: string;
11
+ exchange: string;
12
+ shares: number;
13
+ avgCost?: number;
14
+ currency: string;
15
+ dateAcquired?: string;
16
+ /** Optional account/portfolio identifier from the broker */
17
+ accountId?: string;
18
+ /** Full security name from broker */
19
+ name?: string;
20
+ /** Asset type: STK, ETF, OPT, FUT, BOND, etc. */
21
+ assetCategory?: string;
22
+ /** ISIN identifier */
23
+ isin?: string;
24
+ /** Current market price from broker snapshot */
25
+ markPrice?: number;
26
+ /** Total market value from broker */
27
+ marketValue?: number;
28
+ /** Unrealized P&L from broker */
29
+ unrealizedPnl?: number;
30
+ /** FX rate to account base currency */
31
+ fxRateToBase?: number;
32
+ /** Position side: "long" or "short" */
33
+ side?: "long" | "short";
34
+ /** Contract multiplier (e.g. 100 for options) */
35
+ multiplier?: number;
36
+ /** Percentage of portfolio NAV */
37
+ percentOfNav?: number;
38
+ /** Serializable broker contract metadata */
39
+ brokerContract?: BrokerContractRef;
40
+ }
41
+
42
+ export interface BrokerConfigFieldOption {
43
+ label: string;
44
+ value: string;
45
+ description?: string;
46
+ }
47
+
48
+ export interface BrokerConfigField {
49
+ key: string;
50
+ label: string;
51
+ type: "text" | "password" | "file" | "select" | "number";
52
+ required: boolean;
53
+ placeholder?: string;
54
+ defaultValue?: string;
55
+ options?: BrokerConfigFieldOption[];
56
+ dependsOn?: { key: string; value: string };
57
+ }
58
+
59
+ export interface BrokerConnectionStatus {
60
+ state: "disconnected" | "connecting" | "connected" | "error";
61
+ message?: string;
62
+ mode?: string;
63
+ updatedAt: number;
64
+ }
65
+
66
+ export interface BrokerAdapter {
67
+ readonly id: string;
68
+ readonly name: string;
69
+ readonly cachePolicy?: CachePolicyMap;
70
+ validate(instance: BrokerInstanceConfig): Promise<boolean>;
71
+ importPositions(instance: BrokerInstanceConfig): Promise<BrokerPosition[]>;
72
+ configSchema: BrokerConfigField[];
73
+ connect?(instance: BrokerInstanceConfig): Promise<void>;
74
+ disconnect?(instance: BrokerInstanceConfig): Promise<void>;
75
+ getStatus?(instance: BrokerInstanceConfig): BrokerConnectionStatus;
76
+ listAccounts?(instance: BrokerInstanceConfig): Promise<BrokerAccount[]>;
77
+ searchInstruments?(query: string, instance: BrokerInstanceConfig): Promise<InstrumentSearchResult[]>;
78
+ getTickerFinancials?(ticker: string, instance: BrokerInstanceConfig, exchange?: string, instrument?: BrokerContractRef | null): Promise<TickerFinancials>;
79
+ getQuote?(ticker: string, instance: BrokerInstanceConfig, exchange?: string, instrument?: BrokerContractRef | null): Promise<Quote>;
80
+ getPriceHistory?(ticker: string, instance: BrokerInstanceConfig, exchange: string, range: TimeRange, instrument?: BrokerContractRef | null): Promise<PricePoint[]>;
81
+ /** Fetch higher-resolution price data for a specific date window (e.g. when zoomed in). */
82
+ getDetailedPriceHistory?(ticker: string, instance: BrokerInstanceConfig, exchange: string, startDate: Date, endDate: Date, barSize: string, instrument?: BrokerContractRef | null): Promise<PricePoint[]>;
83
+ getOptionsChain?(ticker: string, instance: BrokerInstanceConfig, exchange?: string, expirationDate?: number, instrument?: BrokerContractRef | null): Promise<OptionsChain>;
84
+ subscribeQuotes?(
85
+ instance: BrokerInstanceConfig,
86
+ targets: QuoteSubscriptionTarget[],
87
+ onQuote: (target: QuoteSubscriptionTarget, quote: Quote) => void,
88
+ ): () => void;
89
+ listOpenOrders?(instance: BrokerInstanceConfig): Promise<BrokerOrder[]>;
90
+ listExecutions?(instance: BrokerInstanceConfig): Promise<BrokerExecution[]>;
91
+ previewOrder?(instance: BrokerInstanceConfig, request: BrokerOrderRequest): Promise<BrokerOrderPreview>;
92
+ placeOrder?(instance: BrokerInstanceConfig, request: BrokerOrderRequest): Promise<BrokerOrder>;
93
+ modifyOrder?(instance: BrokerInstanceConfig, orderId: number, request: BrokerOrderRequest): Promise<BrokerOrder>;
94
+ cancelOrder?(instance: BrokerInstanceConfig, orderId: number): Promise<void>;
95
+ }
96
+
97
+ export function resolveBrokerConfigFields(
98
+ adapter: BrokerAdapter,
99
+ values: Record<string, unknown> = {},
100
+ ): BrokerConfigField[] {
101
+ return adapter.configSchema.filter((field) => {
102
+ if (!field.dependsOn) return true;
103
+ return String(values[field.dependsOn.key] ?? "") === field.dependsOn.value;
104
+ });
105
+ }