opencandle 0.1.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 (228) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +150 -0
  3. package/dist/analysts/orchestrator.d.ts +9 -0
  4. package/dist/analysts/orchestrator.js +100 -0
  5. package/dist/analysts/orchestrator.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +122 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/config.d.ts +24 -0
  10. package/dist/config.js +76 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/index.d.ts +5 -0
  13. package/dist/index.js +6 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/infra/browser.d.ts +27 -0
  16. package/dist/infra/browser.js +102 -0
  17. package/dist/infra/browser.js.map +1 -0
  18. package/dist/infra/cache.d.ts +18 -0
  19. package/dist/infra/cache.js +42 -0
  20. package/dist/infra/cache.js.map +1 -0
  21. package/dist/infra/http-client.d.ts +13 -0
  22. package/dist/infra/http-client.js +54 -0
  23. package/dist/infra/http-client.js.map +1 -0
  24. package/dist/infra/index.d.ts +5 -0
  25. package/dist/infra/index.js +6 -0
  26. package/dist/infra/index.js.map +1 -0
  27. package/dist/infra/open-url.d.ts +1 -0
  28. package/dist/infra/open-url.js +29 -0
  29. package/dist/infra/open-url.js.map +1 -0
  30. package/dist/infra/opencandle-paths.d.ts +11 -0
  31. package/dist/infra/opencandle-paths.js +48 -0
  32. package/dist/infra/opencandle-paths.js.map +1 -0
  33. package/dist/infra/rate-limiter.d.ts +7 -0
  34. package/dist/infra/rate-limiter.js +38 -0
  35. package/dist/infra/rate-limiter.js.map +1 -0
  36. package/dist/memory/index.d.ts +5 -0
  37. package/dist/memory/index.js +5 -0
  38. package/dist/memory/index.js.map +1 -0
  39. package/dist/memory/preference-extractor.d.ts +6 -0
  40. package/dist/memory/preference-extractor.js +88 -0
  41. package/dist/memory/preference-extractor.js.map +1 -0
  42. package/dist/memory/retrieval.d.ts +8 -0
  43. package/dist/memory/retrieval.js +61 -0
  44. package/dist/memory/retrieval.js.map +1 -0
  45. package/dist/memory/sqlite.d.ts +5 -0
  46. package/dist/memory/sqlite.js +95 -0
  47. package/dist/memory/sqlite.js.map +1 -0
  48. package/dist/memory/storage.d.ts +47 -0
  49. package/dist/memory/storage.js +124 -0
  50. package/dist/memory/storage.js.map +1 -0
  51. package/dist/onboarding/state.d.ts +8 -0
  52. package/dist/onboarding/state.js +31 -0
  53. package/dist/onboarding/state.js.map +1 -0
  54. package/dist/pi/opencandle-extension.d.ts +2 -0
  55. package/dist/pi/opencandle-extension.js +205 -0
  56. package/dist/pi/opencandle-extension.js.map +1 -0
  57. package/dist/pi/session.d.ts +10 -0
  58. package/dist/pi/session.js +28 -0
  59. package/dist/pi/session.js.map +1 -0
  60. package/dist/pi/setup.d.ts +10 -0
  61. package/dist/pi/setup.js +357 -0
  62. package/dist/pi/setup.js.map +1 -0
  63. package/dist/pi/tool-adapter.d.ts +5 -0
  64. package/dist/pi/tool-adapter.js +17 -0
  65. package/dist/pi/tool-adapter.js.map +1 -0
  66. package/dist/prompts/workflow-prompts.d.ts +9 -0
  67. package/dist/prompts/workflow-prompts.js +202 -0
  68. package/dist/prompts/workflow-prompts.js.map +1 -0
  69. package/dist/providers/alpha-vantage.d.ts +4 -0
  70. package/dist/providers/alpha-vantage.js +122 -0
  71. package/dist/providers/alpha-vantage.js.map +1 -0
  72. package/dist/providers/coingecko.d.ts +3 -0
  73. package/dist/providers/coingecko.js +53 -0
  74. package/dist/providers/coingecko.js.map +1 -0
  75. package/dist/providers/fear-greed.d.ts +2 -0
  76. package/dist/providers/fear-greed.js +26 -0
  77. package/dist/providers/fear-greed.js.map +1 -0
  78. package/dist/providers/fred.d.ts +2 -0
  79. package/dist/providers/fred.js +37 -0
  80. package/dist/providers/fred.js.map +1 -0
  81. package/dist/providers/index.d.ts +7 -0
  82. package/dist/providers/index.js +8 -0
  83. package/dist/providers/index.js.map +1 -0
  84. package/dist/providers/reddit.d.ts +9 -0
  85. package/dist/providers/reddit.js +69 -0
  86. package/dist/providers/reddit.js.map +1 -0
  87. package/dist/providers/sec-edgar.d.ts +9 -0
  88. package/dist/providers/sec-edgar.js +59 -0
  89. package/dist/providers/sec-edgar.js.map +1 -0
  90. package/dist/providers/yahoo-finance.d.ts +17 -0
  91. package/dist/providers/yahoo-finance.js +231 -0
  92. package/dist/providers/yahoo-finance.js.map +1 -0
  93. package/dist/routing/classify-intent.d.ts +2 -0
  94. package/dist/routing/classify-intent.js +147 -0
  95. package/dist/routing/classify-intent.js.map +1 -0
  96. package/dist/routing/defaults.d.ts +7 -0
  97. package/dist/routing/defaults.js +26 -0
  98. package/dist/routing/defaults.js.map +1 -0
  99. package/dist/routing/entity-extractor.d.ts +3 -0
  100. package/dist/routing/entity-extractor.js +130 -0
  101. package/dist/routing/entity-extractor.js.map +1 -0
  102. package/dist/routing/index.d.ts +5 -0
  103. package/dist/routing/index.js +5 -0
  104. package/dist/routing/index.js.map +1 -0
  105. package/dist/routing/slot-resolver.d.ts +15 -0
  106. package/dist/routing/slot-resolver.js +120 -0
  107. package/dist/routing/slot-resolver.js.map +1 -0
  108. package/dist/routing/types.d.ts +51 -0
  109. package/dist/routing/types.js +2 -0
  110. package/dist/routing/types.js.map +1 -0
  111. package/dist/system-prompt.d.ts +1 -0
  112. package/dist/system-prompt.js +49 -0
  113. package/dist/system-prompt.js.map +1 -0
  114. package/dist/tool-kit.d.ts +19 -0
  115. package/dist/tool-kit.js +20 -0
  116. package/dist/tool-kit.js.map +1 -0
  117. package/dist/tools/fundamentals/company-overview.d.ts +7 -0
  118. package/dist/tools/fundamentals/company-overview.js +40 -0
  119. package/dist/tools/fundamentals/company-overview.js.map +1 -0
  120. package/dist/tools/fundamentals/comps.d.ts +22 -0
  121. package/dist/tools/fundamentals/comps.js +110 -0
  122. package/dist/tools/fundamentals/comps.js.map +1 -0
  123. package/dist/tools/fundamentals/dcf.d.ts +46 -0
  124. package/dist/tools/fundamentals/dcf.js +184 -0
  125. package/dist/tools/fundamentals/dcf.js.map +1 -0
  126. package/dist/tools/fundamentals/earnings.d.ts +7 -0
  127. package/dist/tools/fundamentals/earnings.js +33 -0
  128. package/dist/tools/fundamentals/earnings.js.map +1 -0
  129. package/dist/tools/fundamentals/financials.d.ts +7 -0
  130. package/dist/tools/fundamentals/financials.js +37 -0
  131. package/dist/tools/fundamentals/financials.js.map +1 -0
  132. package/dist/tools/fundamentals/sec-filings.d.ts +8 -0
  133. package/dist/tools/fundamentals/sec-filings.js +40 -0
  134. package/dist/tools/fundamentals/sec-filings.js.map +1 -0
  135. package/dist/tools/index.d.ts +2 -0
  136. package/dist/tools/index.js +51 -0
  137. package/dist/tools/index.js.map +1 -0
  138. package/dist/tools/macro/fear-greed.d.ts +5 -0
  139. package/dist/tools/macro/fear-greed.js +26 -0
  140. package/dist/tools/macro/fear-greed.js.map +1 -0
  141. package/dist/tools/macro/fred-data.d.ts +8 -0
  142. package/dist/tools/macro/fred-data.js +34 -0
  143. package/dist/tools/macro/fred-data.js.map +1 -0
  144. package/dist/tools/market/crypto-history.d.ts +8 -0
  145. package/dist/tools/market/crypto-history.js +32 -0
  146. package/dist/tools/market/crypto-history.js.map +1 -0
  147. package/dist/tools/market/crypto-price.d.ts +7 -0
  148. package/dist/tools/market/crypto-price.js +42 -0
  149. package/dist/tools/market/crypto-price.js.map +1 -0
  150. package/dist/tools/market/search-ticker.d.ts +6 -0
  151. package/dist/tools/market/search-ticker.js +33 -0
  152. package/dist/tools/market/search-ticker.js.map +1 -0
  153. package/dist/tools/market/stock-history.d.ts +9 -0
  154. package/dist/tools/market/stock-history.js +35 -0
  155. package/dist/tools/market/stock-history.js.map +1 -0
  156. package/dist/tools/market/stock-quote.d.ts +7 -0
  157. package/dist/tools/market/stock-quote.js +32 -0
  158. package/dist/tools/market/stock-quote.js.map +1 -0
  159. package/dist/tools/options/greeks.d.ts +14 -0
  160. package/dist/tools/options/greeks.js +65 -0
  161. package/dist/tools/options/greeks.js.map +1 -0
  162. package/dist/tools/options/option-chain.d.ts +9 -0
  163. package/dist/tools/options/option-chain.js +61 -0
  164. package/dist/tools/options/option-chain.js.map +1 -0
  165. package/dist/tools/portfolio/correlation.d.ts +10 -0
  166. package/dist/tools/portfolio/correlation.js +122 -0
  167. package/dist/tools/portfolio/correlation.js.map +1 -0
  168. package/dist/tools/portfolio/predictions.d.ts +49 -0
  169. package/dist/tools/portfolio/predictions.js +171 -0
  170. package/dist/tools/portfolio/predictions.js.map +1 -0
  171. package/dist/tools/portfolio/risk-analysis.d.ts +12 -0
  172. package/dist/tools/portfolio/risk-analysis.js +113 -0
  173. package/dist/tools/portfolio/risk-analysis.js.map +1 -0
  174. package/dist/tools/portfolio/tracker.d.ts +10 -0
  175. package/dist/tools/portfolio/tracker.js +125 -0
  176. package/dist/tools/portfolio/tracker.js.map +1 -0
  177. package/dist/tools/portfolio/watchlist.d.ts +10 -0
  178. package/dist/tools/portfolio/watchlist.js +120 -0
  179. package/dist/tools/portfolio/watchlist.js.map +1 -0
  180. package/dist/tools/sentiment/news-sentiment.d.ts +7 -0
  181. package/dist/tools/sentiment/news-sentiment.js +57 -0
  182. package/dist/tools/sentiment/news-sentiment.js.map +1 -0
  183. package/dist/tools/sentiment/reddit-sentiment.d.ts +8 -0
  184. package/dist/tools/sentiment/reddit-sentiment.js +37 -0
  185. package/dist/tools/sentiment/reddit-sentiment.js.map +1 -0
  186. package/dist/tools/technical/backtest.d.ts +26 -0
  187. package/dist/tools/technical/backtest.js +190 -0
  188. package/dist/tools/technical/backtest.js.map +1 -0
  189. package/dist/tools/technical/indicators.d.ts +23 -0
  190. package/dist/tools/technical/indicators.js +212 -0
  191. package/dist/tools/technical/indicators.js.map +1 -0
  192. package/dist/types/fundamentals.d.ts +44 -0
  193. package/dist/types/fundamentals.js +2 -0
  194. package/dist/types/fundamentals.js.map +1 -0
  195. package/dist/types/index.d.ts +7 -0
  196. package/dist/types/index.js +2 -0
  197. package/dist/types/index.js.map +1 -0
  198. package/dist/types/macro.d.ts +24 -0
  199. package/dist/types/macro.js +14 -0
  200. package/dist/types/macro.js.map +1 -0
  201. package/dist/types/market.d.ts +41 -0
  202. package/dist/types/market.js +2 -0
  203. package/dist/types/market.js.map +1 -0
  204. package/dist/types/options.d.ts +33 -0
  205. package/dist/types/options.js +2 -0
  206. package/dist/types/options.js.map +1 -0
  207. package/dist/types/portfolio.d.ts +44 -0
  208. package/dist/types/portfolio.js +2 -0
  209. package/dist/types/portfolio.js.map +1 -0
  210. package/dist/types/sentiment.d.ts +24 -0
  211. package/dist/types/sentiment.js +2 -0
  212. package/dist/types/sentiment.js.map +1 -0
  213. package/dist/workflows/compare-assets.d.ts +3 -0
  214. package/dist/workflows/compare-assets.js +14 -0
  215. package/dist/workflows/compare-assets.js.map +1 -0
  216. package/dist/workflows/index.d.ts +4 -0
  217. package/dist/workflows/index.js +4 -0
  218. package/dist/workflows/index.js.map +1 -0
  219. package/dist/workflows/options-screener.d.ts +3 -0
  220. package/dist/workflows/options-screener.js +22 -0
  221. package/dist/workflows/options-screener.js.map +1 -0
  222. package/dist/workflows/portfolio-builder.d.ts +3 -0
  223. package/dist/workflows/portfolio-builder.js +26 -0
  224. package/dist/workflows/portfolio-builder.js.map +1 -0
  225. package/dist/workflows/types.d.ts +4 -0
  226. package/dist/workflows/types.js +2 -0
  227. package/dist/workflows/types.js.map +1 -0
  228. package/package.json +97 -0
@@ -0,0 +1,231 @@
1
+ import { httpGet } from "../infra/http-client.js";
2
+ import { cache, TTL } from "../infra/cache.js";
3
+ import { rateLimiter } from "../infra/rate-limiter.js";
4
+ import { StealthBrowser } from "../infra/browser.js";
5
+ import { computeGreeks } from "../tools/options/greeks.js";
6
+ const BASE_URL = "https://query1.finance.yahoo.com/v8/finance/chart";
7
+ export async function getQuote(symbol) {
8
+ const cacheKey = `yahoo:quote:${symbol}`;
9
+ const cached = cache.get(cacheKey);
10
+ if (cached)
11
+ return cached;
12
+ await rateLimiter.acquire("yahoo");
13
+ const url = `${BASE_URL}/${encodeURIComponent(symbol)}?interval=1d&range=1d`;
14
+ const data = await httpGet(url, {
15
+ headers: { "User-Agent": "OpenCandle/1.0" },
16
+ });
17
+ if (data.chart.error) {
18
+ throw new Error(`Yahoo Finance: ${data.chart.error.description}`);
19
+ }
20
+ const result = data.chart.result[0];
21
+ const meta = result.meta;
22
+ const indicators = result.indicators.quote[0];
23
+ const price = meta.regularMarketPrice ?? 0;
24
+ const prevClose = meta.chartPreviousClose ?? meta.previousClose ?? price;
25
+ const change = price - prevClose;
26
+ const changePercent = prevClose !== 0 ? (change / prevClose) * 100 : 0;
27
+ // Open price: try meta first, fall back to indicators
28
+ const open = meta.regularMarketOpen ?? indicators?.open?.[0] ?? price;
29
+ const quote = {
30
+ symbol: meta.symbol,
31
+ price,
32
+ change,
33
+ changePercent,
34
+ open,
35
+ high: meta.regularMarketDayHigh ?? indicators?.high?.[0] ?? price,
36
+ low: meta.regularMarketDayLow ?? indicators?.low?.[0] ?? price,
37
+ previousClose: prevClose,
38
+ volume: meta.regularMarketVolume ?? 0,
39
+ marketCap: meta.marketCap ?? 0,
40
+ pe: null, // Not in chart endpoint
41
+ week52High: meta.fiftyTwoWeekHigh ?? 0,
42
+ week52Low: meta.fiftyTwoWeekLow ?? 0,
43
+ timestamp: Date.now(),
44
+ };
45
+ cache.set(cacheKey, quote, TTL.QUOTE);
46
+ return quote;
47
+ }
48
+ export async function getHistory(symbol, range = "6mo", interval = "1d") {
49
+ const cacheKey = `yahoo:history:${symbol}:${range}:${interval}`;
50
+ const cached = cache.get(cacheKey);
51
+ if (cached)
52
+ return cached;
53
+ await rateLimiter.acquire("yahoo");
54
+ const url = `${BASE_URL}/${encodeURIComponent(symbol)}?interval=${interval}&range=${range}`;
55
+ const data = await httpGet(url, {
56
+ headers: { "User-Agent": "OpenCandle/1.0" },
57
+ });
58
+ if (data.chart.error) {
59
+ throw new Error(`Yahoo Finance: ${data.chart.error.description}`);
60
+ }
61
+ const result = data.chart.result[0];
62
+ const timestamps = result.timestamp;
63
+ const quotes = result.indicators.quote[0];
64
+ const ohlcv = timestamps
65
+ .map((ts, i) => ({
66
+ date: new Date(ts * 1000).toISOString().split("T")[0],
67
+ open: quotes.open[i],
68
+ high: quotes.high[i],
69
+ low: quotes.low[i],
70
+ close: quotes.close[i],
71
+ volume: quotes.volume[i],
72
+ }))
73
+ .filter((bar) => bar.open != null && bar.close != null);
74
+ cache.set(cacheKey, ohlcv, TTL.HISTORY);
75
+ return ohlcv;
76
+ }
77
+ // --- Options Chain (v7 API with crumb+cookie auth) ---
78
+ const BROWSER_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
79
+ let cachedCrumb = null;
80
+ export function clearCrumbCache() {
81
+ cachedCrumb = null;
82
+ }
83
+ export async function getYahooCrumb() {
84
+ if (cachedCrumb && Date.now() < cachedCrumb.expiresAt) {
85
+ return { crumb: cachedCrumb.crumb, cookie: cachedCrumb.cookie };
86
+ }
87
+ // Step 1: Hit fc.yahoo.com to get a session cookie
88
+ const cookieRes = await fetch("https://fc.yahoo.com/t", {
89
+ headers: { "User-Agent": BROWSER_UA },
90
+ });
91
+ const setCookie = cookieRes.headers.get("set-cookie") ?? "";
92
+ const cookie = setCookie.split(";")[0]; // Extract just the cookie value
93
+ // Step 2: Use the cookie to get a crumb
94
+ const crumbRes = await fetch("https://query2.finance.yahoo.com/v1/test/getcrumb", {
95
+ headers: { "User-Agent": BROWSER_UA, Cookie: cookie },
96
+ });
97
+ const crumb = await crumbRes.text();
98
+ if (!crumb || crumb.includes("Unauthorized")) {
99
+ throw new Error("Failed to acquire Yahoo Finance crumb");
100
+ }
101
+ cachedCrumb = { crumb, cookie, expiresAt: Date.now() + TTL.CRUMB };
102
+ return { crumb, cookie };
103
+ }
104
+ export async function getOptionsChain(symbol, expiration) {
105
+ const cacheKey = `yahoo:options:${symbol}:${expiration ?? "nearest"}`;
106
+ const cached = cache.get(cacheKey);
107
+ if (cached)
108
+ return cached;
109
+ await rateLimiter.acquire("yahoo");
110
+ const { crumb, cookie } = await getYahooCrumb();
111
+ const dateParam = expiration ? `&date=${expiration}` : "";
112
+ const url = `https://query1.finance.yahoo.com/v7/finance/options/${encodeURIComponent(symbol)}?crumb=${encodeURIComponent(crumb)}${dateParam}`;
113
+ let res = await fetch(url, {
114
+ headers: { "User-Agent": BROWSER_UA, Cookie: cookie },
115
+ });
116
+ // On 401 or 429, refresh crumb and retry once
117
+ if (res.status === 401 || res.status === 429) {
118
+ clearCrumbCache();
119
+ const fresh = await getYahooCrumb();
120
+ const retryUrl = `https://query1.finance.yahoo.com/v7/finance/options/${encodeURIComponent(symbol)}?crumb=${encodeURIComponent(fresh.crumb)}${dateParam}`;
121
+ res = await fetch(retryUrl, {
122
+ headers: { "User-Agent": BROWSER_UA, Cookie: fresh.cookie },
123
+ });
124
+ }
125
+ // If still failing, fall back to stealth browser (bypasses TLS fingerprinting)
126
+ if (!res.ok) {
127
+ const browserData = await fetchOptionsViaBrowser(symbol, expiration);
128
+ if (browserData) {
129
+ const chain = parseOptionsResponse(symbol, browserData);
130
+ cache.set(cacheKey, chain, TTL.OPTIONS_CHAIN);
131
+ return chain;
132
+ }
133
+ throw new Error(`Yahoo Finance options: HTTP ${res.status}`);
134
+ }
135
+ const data = await res.json();
136
+ const chain = parseOptionsResponse(symbol, data);
137
+ cache.set(cacheKey, chain, TTL.OPTIONS_CHAIN);
138
+ return chain;
139
+ }
140
+ /**
141
+ * Compute time to expiry in years from a Yahoo expiration timestamp (midnight UTC).
142
+ * US equity options expire at 4:00 PM ET. During EDT that is 20:00 UTC.
143
+ * We use 21:00 UTC (4 PM EST / 5 PM EDT) as a conservative close offset
144
+ * and apply a floor of ~1 hour to prevent numerical instability near expiry.
145
+ */
146
+ export function computeTimeToExpiry(expirationTs, nowMs = Date.now()) {
147
+ const MARKET_CLOSE_OFFSET_S = 21 * 3600; // 21:00 UTC ≈ 4 PM ET
148
+ const MIN_TIME_YEARS = 1 / (365 * 24); // ~1 hour floor
149
+ const SECONDS_PER_YEAR = 365 * 24 * 3600;
150
+ const expiryCloseTs = expirationTs + MARKET_CLOSE_OFFSET_S;
151
+ const remainingS = expiryCloseTs - nowMs / 1000;
152
+ if (remainingS <= 0)
153
+ return 0;
154
+ return Math.max(MIN_TIME_YEARS, remainingS / SECONDS_PER_YEAR);
155
+ }
156
+ function parseOptionsResponse(symbol, data) {
157
+ if (data.optionChain.error) {
158
+ throw new Error(`Yahoo Finance options: ${JSON.stringify(data.optionChain.error)}`);
159
+ }
160
+ const result = data.optionChain.result[0];
161
+ const quote = result.quote;
162
+ const underlyingPrice = quote.regularMarketPrice ?? 0;
163
+ const opts = result.options[0];
164
+ const riskFreeRate = 0.05;
165
+ const expirationTs = opts.expirationDate;
166
+ const expirationDate = new Date(expirationTs * 1000).toISOString().split("T")[0];
167
+ const timeYears = computeTimeToExpiry(expirationTs);
168
+ const mapContract = (c, type) => {
169
+ const strike = c.strike ?? c.strike?.raw ?? 0;
170
+ const iv = c.impliedVolatility ?? c.impliedVolatility?.raw ?? 0;
171
+ const greeks = computeGreeks({ type, spot: underlyingPrice, strike, timeYears, iv, riskFreeRate });
172
+ return {
173
+ contractSymbol: c.contractSymbol ?? "",
174
+ type,
175
+ strike,
176
+ expiration: expirationDate,
177
+ bid: c.bid ?? c.bid?.raw ?? 0,
178
+ ask: c.ask ?? c.ask?.raw ?? 0,
179
+ lastPrice: c.lastPrice ?? c.lastPrice?.raw ?? 0,
180
+ volume: c.volume ?? c.volume?.raw ?? 0,
181
+ openInterest: c.openInterest ?? c.openInterest?.raw ?? 0,
182
+ impliedVolatility: iv,
183
+ inTheMoney: c.inTheMoney ?? false,
184
+ greeks,
185
+ };
186
+ };
187
+ const calls = (opts.calls ?? []).map((c) => mapContract(c, "call"));
188
+ const puts = (opts.puts ?? []).map((c) => mapContract(c, "put"));
189
+ const totalCallVolume = calls.reduce((s, c) => s + c.volume, 0);
190
+ const totalPutVolume = puts.reduce((s, c) => s + c.volume, 0);
191
+ return {
192
+ symbol: result.underlyingSymbol,
193
+ underlyingPrice,
194
+ expirationDate,
195
+ expirationDates: result.expirationDates.map((ts) => new Date(ts * 1000).toISOString().split("T")[0]),
196
+ calls,
197
+ puts,
198
+ totalCallVolume,
199
+ totalPutVolume,
200
+ putCallRatio: totalCallVolume > 0 ? totalPutVolume / totalCallVolume : 0,
201
+ fetchedAt: new Date().toISOString(),
202
+ };
203
+ }
204
+ /**
205
+ * Fallback: fetch options data via Camoufox stealth browser.
206
+ * Bypasses Yahoo's TLS fingerprinting and rate limiting.
207
+ */
208
+ async function fetchOptionsViaBrowser(symbol, expiration) {
209
+ try {
210
+ // Establish Yahoo session in browser
211
+ await StealthBrowser.initSession("https://finance.yahoo.com");
212
+ // Get crumb + fetch options from within the browser context
213
+ const dateParam = expiration ? `&date=${expiration}` : "";
214
+ const data = await StealthBrowser.run(async (page) => {
215
+ return page.evaluate(async (params) => {
216
+ const crumbRes = await fetch("https://query2.finance.yahoo.com/v1/test/getcrumb", { credentials: "include" });
217
+ const crumb = await crumbRes.text();
218
+ const url = `https://query1.finance.yahoo.com/v7/finance/options/${params.symbol}?crumb=${encodeURIComponent(crumb)}${params.dateParam}`;
219
+ const res = await fetch(url, { credentials: "include" });
220
+ if (!res.ok)
221
+ return null;
222
+ return res.json();
223
+ }, { symbol, dateParam });
224
+ });
225
+ return data;
226
+ }
227
+ catch {
228
+ return null;
229
+ }
230
+ }
231
+ //# sourceMappingURL=yahoo-finance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yahoo-finance.js","sourceRoot":"","sources":["../../src/providers/yahoo-finance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ClassificationResult } from "./types.js";
2
+ export declare function classifyIntent(input: string): ClassificationResult;
@@ -0,0 +1,147 @@
1
+ import { extractEntities } from "./entity-extractor.js";
2
+ const ANALYSIS_PATTERNS = [
3
+ /^\s*analyze\s+\$?([A-Za-z]{1,5})\s*$/i,
4
+ /^\s*full\s+analysis\s+(?:of\s+)?\$?([A-Za-z]{1,5})\s*$/i,
5
+ /^\s*deep\s+dive\s+(?:on\s+)?\$?([A-Za-z]{1,5})\s*$/i,
6
+ ];
7
+ const RULES = [
8
+ // Exact-match analysis patterns (highest priority)
9
+ {
10
+ workflow: "single_asset_analysis",
11
+ confidence: 1.0,
12
+ test: (input) => ANALYSIS_PATTERNS.some((p) => p.test(input)),
13
+ },
14
+ {
15
+ workflow: "single_asset_analysis",
16
+ confidence: 0.85,
17
+ test: (input, entities) => {
18
+ const lower = input.toLowerCase();
19
+ return (entities.symbols.length === 1 &&
20
+ (/\bis\s+\S+\s+(?:attractive|undervalued|overvalued|cheap|expensive)/i.test(lower) ||
21
+ /\bshould\s+i\s+buy\s+\$?[a-z]{1,5}\b/i.test(lower) ||
22
+ /\bwhat\s+do\s+you\s+think\s+(?:of|about)\s+\$?[a-z]{1,5}\b/i.test(lower)));
23
+ },
24
+ },
25
+ // Options: symbol + option keyword
26
+ {
27
+ workflow: "options_screener",
28
+ confidence: 0.95,
29
+ test: (input, entities) => {
30
+ const lower = input.toLowerCase();
31
+ const hasOptionKeywords = /\bcalls?\b/.test(lower) ||
32
+ /\bputs?\b/.test(lower) ||
33
+ /\boption(?:s)?\s*chain\b/.test(lower) ||
34
+ /\boptions?\b/.test(lower);
35
+ return hasOptionKeywords && entities.symbols.length >= 1;
36
+ },
37
+ },
38
+ // Compare: keyword + 2+ symbols (uppercase)
39
+ {
40
+ workflow: "compare_assets",
41
+ confidence: 0.95,
42
+ test: (input, entities) => {
43
+ const lower = input.toLowerCase();
44
+ const hasCompareKeywords = /\bcompare\b/.test(lower) ||
45
+ /\bvs\.?\b/.test(lower) ||
46
+ /\bversus\b/.test(lower) ||
47
+ /\bwhich\s+is\s+better\b/.test(lower);
48
+ return hasCompareKeywords && entities.symbols.length >= 2;
49
+ },
50
+ },
51
+ // Compare: keyword + lowercase tickers ("Compare aapl and msft")
52
+ {
53
+ workflow: "compare_assets",
54
+ confidence: 0.85,
55
+ test: (input) => {
56
+ const lower = input.toLowerCase();
57
+ return /\bcompare\s+[a-z]{1,5}(?:\s*,?\s*(?:and\s+)?[a-z]{1,5})+/.test(lower);
58
+ },
59
+ },
60
+ // Compare: 2+ uppercase symbols without explicit keyword
61
+ {
62
+ workflow: "compare_assets",
63
+ confidence: 0.8,
64
+ test: (_input, entities) => entities.symbols.length >= 2,
65
+ },
66
+ // Watchlist/tracking: must come before portfolio_builder to catch "show my portfolio"
67
+ {
68
+ workflow: "watchlist_or_tracking",
69
+ confidence: 0.95,
70
+ test: (input) => {
71
+ const lower = input.toLowerCase();
72
+ return (/\bwatchlist\b/.test(lower) ||
73
+ /\bprediction/i.test(lower) ||
74
+ /\bshow\s+my\s+portfolio\b/.test(lower) ||
75
+ /\bmy\s+portfolio\b/.test(lower) ||
76
+ /\btrack\b/.test(lower));
77
+ },
78
+ },
79
+ // Portfolio: budget + invest keyword
80
+ {
81
+ workflow: "portfolio_builder",
82
+ confidence: 0.9,
83
+ test: (input, entities) => {
84
+ const lower = input.toLowerCase();
85
+ return (entities.budget !== undefined &&
86
+ (/\binvest\b/.test(lower) ||
87
+ /\bportfolio\b/.test(lower) ||
88
+ /\ballocat/i.test(lower) ||
89
+ /\bposition/i.test(lower) ||
90
+ /\bbuy\b/.test(lower)));
91
+ },
92
+ },
93
+ // Portfolio: keyword-only (no budget required)
94
+ {
95
+ workflow: "portfolio_builder",
96
+ confidence: 0.8,
97
+ test: (input) => {
98
+ const lower = input.toLowerCase();
99
+ return (/\bportfolio\b/.test(lower) ||
100
+ /\bwhat\s+should\s+i\s+(?:invest|buy)\b/.test(lower) ||
101
+ /\bbuild\s+(?:me\s+)?a?\s*(?:diversified\s+)?.*portfolio\b/.test(lower) ||
102
+ (/\binvest\s+in\b/.test(lower) && /\bwhat\b/.test(lower)));
103
+ },
104
+ },
105
+ // General finance Q&A
106
+ {
107
+ workflow: "general_finance_qa",
108
+ confidence: 0.85,
109
+ test: (input) => {
110
+ const lower = input.toLowerCase();
111
+ return (/^what\s+(?:is|are|does|do)\b/.test(lower) ||
112
+ /^how\s+(?:does|do|is|are)\b/.test(lower) ||
113
+ /^explain\b/.test(lower) ||
114
+ /^define\b/.test(lower) ||
115
+ /\bwhat\s+does\s+\S+\s+mean\b/.test(lower));
116
+ },
117
+ },
118
+ ];
119
+ export function classifyIntent(input) {
120
+ const trimmed = input.trim();
121
+ if (!trimmed) {
122
+ return {
123
+ workflow: "unclassified",
124
+ confidence: 0,
125
+ tier: "rule",
126
+ entities: { symbols: [] },
127
+ };
128
+ }
129
+ const entities = extractEntities(trimmed);
130
+ for (const rule of RULES) {
131
+ if (rule.test(trimmed, entities)) {
132
+ return {
133
+ workflow: rule.workflow,
134
+ confidence: rule.confidence,
135
+ tier: "rule",
136
+ entities,
137
+ };
138
+ }
139
+ }
140
+ return {
141
+ workflow: "unclassified",
142
+ confidence: 0,
143
+ tier: "rule",
144
+ entities,
145
+ };
146
+ }
147
+ //# sourceMappingURL=classify-intent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify-intent.js","sourceRoot":"","sources":["../../src/routing/classify-intent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { PortfolioSlots, OptionsScreenerSlots } from "./types.js";
2
+ export declare const PORTFOLIO_DEFAULTS: Omit<PortfolioSlots, "budget">;
3
+ export declare const OPTIONS_SCREENER_DEFAULTS: Omit<OptionsScreenerSlots, "symbol" | "direction">;
4
+ export declare function parseDteTarget(dteTarget: string): {
5
+ minDays: number;
6
+ maxDays: number;
7
+ } | null;
@@ -0,0 +1,26 @@
1
+ export const PORTFOLIO_DEFAULTS = {
2
+ riskProfile: "balanced",
3
+ timeHorizon: "1y_plus",
4
+ assetScope: "mixed_etf_and_large_cap_equities",
5
+ positionCount: 4,
6
+ maxSinglePositionPct: 35,
7
+ };
8
+ export const OPTIONS_SCREENER_DEFAULTS = {
9
+ dteTarget: "25_to_45_days",
10
+ objective: "balanced_leverage_and_probability",
11
+ moneynessPreference: "atm_to_slightly_otm",
12
+ liquidityMinimum: "high_open_interest_and_tight_spread",
13
+ };
14
+ export function parseDteTarget(dteTarget) {
15
+ const rangeMatch = dteTarget.match(/^(\d+)_to_(\d+)_days$/);
16
+ if (rangeMatch) {
17
+ return { minDays: parseInt(rangeMatch[1], 10), maxDays: parseInt(rangeMatch[2], 10) };
18
+ }
19
+ const plusMatch = dteTarget.match(/^(\d+)_plus_days$/);
20
+ if (plusMatch) {
21
+ const min = parseInt(plusMatch[1], 10);
22
+ return { minDays: min, maxDays: min + 180 };
23
+ }
24
+ return null;
25
+ }
26
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/routing/defaults.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAmC;IAChE,WAAW,EAAE,UAAU;IACvB,WAAW,EAAE,SAAS;IACtB,UAAU,EAAE,kCAAkC;IAC9C,aAAa,EAAE,CAAC;IAChB,oBAAoB,EAAE,EAAE;CACzB,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAuD;IAC3F,SAAS,EAAE,eAAe;IAC1B,SAAS,EAAE,mCAAmC;IAC9C,mBAAmB,EAAE,qBAAqB;IAC1C,gBAAgB,EAAE,qCAAqC;CACxD,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC5D,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACxF,CAAC;IACD,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACvD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ExtractedEntities } from "./types.js";
2
+ export declare function extractEntities(input: string): ExtractedEntities;
3
+ export declare function extractBudget(input: string): number | undefined;
@@ -0,0 +1,130 @@
1
+ const COMMON_WORDS = new Set([
2
+ "I", "A", "AN", "AM", "AS", "AT", "BE", "BY", "DO", "GO", "IF", "IN", "IS",
3
+ "IT", "ME", "MY", "NO", "OF", "ON", "OR", "SO", "TO", "UP", "US", "WE",
4
+ "THE", "AND", "BUT", "FOR", "NOT", "ALL", "ARE", "CAN", "HAD", "HAS", "HER",
5
+ "HIM", "HIS", "HOW", "ITS", "LET", "MAY", "NEW", "NOW", "OLD", "OUR", "OWN",
6
+ "SAY", "SHE", "TOO", "USE", "WAY", "WHO", "BOY", "DID", "GET", "HAS", "HIM",
7
+ "OUT", "PUT", "RUN", "SET", "TOP", "WHY", "BIG", "END", "FAR", "FEW",
8
+ "GOT", "LOW", "MAN", "OFF", "PAY", "TRY", "TWO", "BUY", "ETF", "ETFS",
9
+ // Technical analysis acronyms
10
+ "SMA", "EMA", "RSI", "MACD", "OBV", "ATR", "ADX", "VWAP",
11
+ // Fundamental analysis acronyms
12
+ "DCF", "FCF", "ROE", "ROA", "ROI", "EPS", "NAV", "WACC", "EBIT",
13
+ "BEST", "WHAT", "WITH", "THAT", "THIS", "FROM", "HAVE", "BEEN", "SOME",
14
+ "THEM", "THAN", "LIKE", "JUST", "OVER", "ALSO", "BACK", "MUCH", "MOST",
15
+ "ONLY", "VERY", "WHEN", "COME", "MAKE", "FIND", "HERE", "KNOW", "TAKE",
16
+ "WANT", "GIVE", "GOOD", "CALL", "PUTS", "SAFE", "RISK", "LONG", "TERM",
17
+ "NEXT", "SHOW", "LAST",
18
+ ]);
19
+ export function extractEntities(input) {
20
+ return {
21
+ symbols: extractSymbols(input),
22
+ budget: extractBudget(input),
23
+ maxPremium: extractMaxPremium(input),
24
+ direction: extractDirection(input),
25
+ riskProfile: extractRiskProfile(input),
26
+ dteHint: extractDteHint(input),
27
+ timeHorizon: extractTimeHorizon(input),
28
+ };
29
+ }
30
+ export function extractBudget(input) {
31
+ // Match $10,000 or $10000 or $10k
32
+ const dollarSign = input.match(/\$\s*([\d,]+(?:\.\d+)?)\s*([kK])?\b/);
33
+ if (dollarSign) {
34
+ const base = parseFloat(dollarSign[1].replace(/,/g, ""));
35
+ return dollarSign[2] ? base * 1000 : base;
36
+ }
37
+ // Match "10k" or "10K" standalone
38
+ const kNotation = input.match(/\b(\d+(?:\.\d+)?)\s*[kK]\b/);
39
+ if (kNotation) {
40
+ return parseFloat(kNotation[1]) * 1000;
41
+ }
42
+ // Match "10000 dollars" or "10,000 dollars"
43
+ const dollarWord = input.match(/\b([\d,]+(?:\.\d+)?)\s+dollars?\b/i);
44
+ if (dollarWord) {
45
+ return parseFloat(dollarWord[1].replace(/,/g, ""));
46
+ }
47
+ return undefined;
48
+ }
49
+ function extractSymbols(input) {
50
+ const symbols = [];
51
+ // Match $TICKER patterns
52
+ const dollarTickers = input.matchAll(/\$([A-Za-z]{1,5})\b/g);
53
+ for (const match of dollarTickers) {
54
+ symbols.push(match[1].toUpperCase());
55
+ }
56
+ // Match standalone uppercase tickers (1-5 chars, all caps)
57
+ const words = input.split(/[\s,]+/);
58
+ for (const word of words) {
59
+ const cleaned = word.replace(/[^A-Za-z]/g, "");
60
+ if (cleaned.length >= 1 &&
61
+ cleaned.length <= 5 &&
62
+ cleaned === cleaned.toUpperCase() &&
63
+ /^[A-Z]+$/.test(cleaned) &&
64
+ !COMMON_WORDS.has(cleaned) &&
65
+ !symbols.includes(cleaned)) {
66
+ symbols.push(cleaned);
67
+ }
68
+ }
69
+ return symbols;
70
+ }
71
+ function extractMaxPremium(input) {
72
+ const lower = input.toLowerCase();
73
+ if (!/\bpremium\b/.test(lower))
74
+ return undefined;
75
+ const under = input.match(/\b(?:under|below|less\s+than|max(?:imum)?|up\s+to)\s+\$?\s*([\d,]+(?:\.\d+)?)\s*([kK])?\b/i);
76
+ if (under) {
77
+ const base = parseFloat(under[1].replace(/,/g, ""));
78
+ if (isNaN(base))
79
+ return undefined;
80
+ return under[2] ? base * 1000 : base;
81
+ }
82
+ const trailing = input.match(/\$\s*([\d,]+(?:\.\d+)?)\s*([kK])?\s*(?:premium|max\s*premium)\b/i);
83
+ if (trailing) {
84
+ const base = parseFloat(trailing[1].replace(/,/g, ""));
85
+ if (isNaN(base))
86
+ return undefined;
87
+ return trailing[2] ? base * 1000 : base;
88
+ }
89
+ return undefined;
90
+ }
91
+ function extractDirection(input) {
92
+ const lower = input.toLowerCase();
93
+ if (/\bcalls?\b/.test(lower) || /\bbullish\b/.test(lower))
94
+ return "bullish";
95
+ if (/\bputs?\b/.test(lower) || /\bbearish\b/.test(lower))
96
+ return "bearish";
97
+ return undefined;
98
+ }
99
+ function extractRiskProfile(input) {
100
+ const lower = input.toLowerCase();
101
+ if (/\bconservative\b/.test(lower) || /\brisk\s*averse\b/.test(lower) || /\bsafe[r]?\b/.test(lower)) {
102
+ return "conservative";
103
+ }
104
+ if (/\baggressive\b/.test(lower) || /\bhigh\s*risk\b/.test(lower)) {
105
+ return "aggressive";
106
+ }
107
+ if (/\bbalanced\b/.test(lower) || /\bmoderate\b/.test(lower)) {
108
+ return "balanced";
109
+ }
110
+ return undefined;
111
+ }
112
+ function extractDteHint(input) {
113
+ const lower = input.toLowerCase();
114
+ if (/\bleaps?\b/i.test(lower) || /\blong[\s-]*dated\b/.test(lower))
115
+ return "leaps";
116
+ if (/\bmonth\b/.test(lower))
117
+ return "month";
118
+ if (/\bweek(?:ly|s?)?\b/.test(lower))
119
+ return "week";
120
+ return undefined;
121
+ }
122
+ function extractTimeHorizon(input) {
123
+ const lower = input.toLowerCase();
124
+ if (/\bshort[\s-]*term\b/.test(lower) || /\bday[\s-]*trad/i.test(lower))
125
+ return "short";
126
+ if (/\blong[\s-]*term\b/.test(lower) || /\bbuy[\s-]*and[\s-]*hold\b/.test(lower))
127
+ return "long";
128
+ return undefined;
129
+ }
130
+ //# sourceMappingURL=entity-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-extractor.js","sourceRoot":"","sources":["../../src/routing/entity-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { classifyIntent } from "./classify-intent.js";
2
+ export { extractEntities, extractBudget } from "./entity-extractor.js";
3
+ export { resolvePortfolioSlots, resolveOptionsScreenerSlots } from "./slot-resolver.js";
4
+ export { PORTFOLIO_DEFAULTS, OPTIONS_SCREENER_DEFAULTS, parseDteTarget } from "./defaults.js";
5
+ export type { WorkflowType, ClassificationResult, ExtractedEntities, PortfolioSlots, OptionsScreenerSlots, CompareAssetsSlots, SlotResolution, SlotSource, } from "./types.js";
@@ -0,0 +1,5 @@
1
+ export { classifyIntent } from "./classify-intent.js";
2
+ export { extractEntities, extractBudget } from "./entity-extractor.js";
3
+ export { resolvePortfolioSlots, resolveOptionsScreenerSlots } from "./slot-resolver.js";
4
+ export { PORTFOLIO_DEFAULTS, OPTIONS_SCREENER_DEFAULTS, parseDteTarget } from "./defaults.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { ExtractedEntities, PortfolioSlots, OptionsScreenerSlots, SlotResolution } from "./types.js";
2
+ interface Preferences {
3
+ riskProfile?: string;
4
+ timeHorizon?: string;
5
+ assetScope?: string;
6
+ positionCount?: number;
7
+ maxSinglePositionPct?: number;
8
+ dteTarget?: string;
9
+ objective?: string;
10
+ moneynessPreference?: string;
11
+ liquidityMinimum?: string;
12
+ }
13
+ export declare function resolvePortfolioSlots(entities: ExtractedEntities, preferences?: Preferences): SlotResolution<PortfolioSlots>;
14
+ export declare function resolveOptionsScreenerSlots(entities: ExtractedEntities, preferences?: Preferences): SlotResolution<OptionsScreenerSlots>;
15
+ export {};