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,57 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { getSubredditPosts } from "../../providers/reddit.js";
3
+ const params = Type.Object({
4
+ topic: Type.String({
5
+ description: "Topic or ticker to search for news sentiment (e.g. AAPL, bitcoin, inflation)",
6
+ }),
7
+ });
8
+ export const newsSentimentTool = {
9
+ name: "get_reddit_discussions",
10
+ label: "Reddit Financial Discussions",
11
+ description: "Search financial Reddit communities (r/stocks, r/investing) for recent discussions about a topic. Useful for gauging retail sentiment, but not a substitute for news or institutional analysis.",
12
+ parameters: params,
13
+ async execute(toolCallId, args) {
14
+ // Use r/stocks and r/investing as news proxies
15
+ const subreddits = ["stocks", "investing"];
16
+ const allPosts = [];
17
+ const allMentions = [];
18
+ for (const sub of subreddits) {
19
+ try {
20
+ const result = await getSubredditPosts(sub, 25);
21
+ // Filter posts that mention the topic
22
+ const relevant = result.posts.filter((p) => p.title.toLowerCase().includes(args.topic.toLowerCase()));
23
+ allPosts.push(...relevant);
24
+ allMentions.push(...result.topMentions);
25
+ }
26
+ catch {
27
+ // Continue with other subreddits if one fails
28
+ }
29
+ }
30
+ const uniqueMentions = [...new Set(allMentions)];
31
+ const text = [
32
+ `**Reddit Discussions for "${args.topic}"** — ${allPosts.length} relevant posts found`,
33
+ uniqueMentions.length > 0
34
+ ? `Related tickers: ${uniqueMentions.map((t) => `$${t}`).join(", ")}`
35
+ : "",
36
+ "",
37
+ ...allPosts.slice(0, 10).map((p) => ` ⬆${p.score} 💬${p.comments} — ${p.title.slice(0, 100)}`),
38
+ allPosts.length === 0 ? "No relevant discussions found. Try broader search terms." : "",
39
+ ]
40
+ .filter(Boolean)
41
+ .join("\n");
42
+ return {
43
+ content: [{ type: "text", text }],
44
+ details: {
45
+ subreddit: "stocks+investing",
46
+ postCount: allPosts.length,
47
+ posts: allPosts,
48
+ topMentions: uniqueMentions,
49
+ sentimentScore: 0,
50
+ bullishCount: 0,
51
+ bearishCount: 0,
52
+ fetchedAt: new Date().toISOString(),
53
+ },
54
+ };
55
+ },
56
+ };
57
+ //# sourceMappingURL=news-sentiment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"news-sentiment.js","sourceRoot":"","sources":["../../../src/tools/sentiment/news-sentiment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACzB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;QACjB,WAAW,EAAE,8EAA8E;KAC5F,CAAC;CACH,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAoD;IAChF,IAAI,EAAE,wBAAwB;IAC9B,KAAK,EAAE,8BAA8B;IACrC,WAAW,EACT,iMAAiM;IACnM,UAAU,EAAE,MAAM;IAClB,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI;QAC5B,+CAA+C;QAC/C,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAmC,EAAE,CAAC;QACpD,MAAM,WAAW,GAAa,EAAE,CAAC;QAEjC,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAChD,sCAAsC;gBACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAClC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAChE,CAAC;gBACF,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;gBAC3B,WAAW,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,8CAA8C;YAChD,CAAC;QACH,CAAC;QAED,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG;YACX,6BAA6B,IAAI,CAAC,KAAK,SAAS,QAAQ,CAAC,MAAM,uBAAuB;YACtF,cAAc,CAAC,MAAM,GAAG,CAAC;gBACvB,CAAC,CAAC,oBAAoB,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACrE,CAAC,CAAC,EAAE;YACN,EAAE;YACF,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAClE;YACD,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,0DAA0D,CAAC,CAAC,CAAC,EAAE;SACxF;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACjC,OAAO,EAAE;gBACP,SAAS,EAAE,kBAAkB;gBAC7B,SAAS,EAAE,QAAQ,CAAC,MAAM;gBAC1B,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,cAAc;gBAC3B,cAAc,EAAE,CAAC;gBACjB,YAAY,EAAE,CAAC;gBACf,YAAY,EAAE,CAAC;gBACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import type { RedditSentimentResult } from "../../types/sentiment.js";
3
+ declare const params: import("@sinclair/typebox").TObject<{
4
+ subreddit: import("@sinclair/typebox").TString;
5
+ limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
6
+ }>;
7
+ export declare const redditSentimentTool: AgentTool<typeof params, RedditSentimentResult>;
8
+ export {};
@@ -0,0 +1,37 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { getSubredditPosts } from "../../providers/reddit.js";
3
+ const params = Type.Object({
4
+ subreddit: Type.String({
5
+ description: "Subreddit name (e.g. wallstreetbets, stocks, investing, cryptocurrency, options)",
6
+ }),
7
+ limit: Type.Optional(Type.Number({ description: "Number of posts to fetch. Default: 25, max: 100" })),
8
+ });
9
+ export const redditSentimentTool = {
10
+ name: "get_reddit_sentiment",
11
+ label: "Reddit Sentiment",
12
+ description: "Get hot posts from a finance subreddit for sentiment analysis. Returns post titles, scores, comment counts, and detected ticker mentions. Use for retail sentiment.",
13
+ parameters: params,
14
+ async execute(toolCallId, args) {
15
+ const limit = Math.min(args.limit ?? 25, 100);
16
+ const result = await getSubredditPosts(args.subreddit, limit);
17
+ const sentimentLabel = result.sentimentScore > 0.3 ? "Bullish" :
18
+ result.sentimentScore < -0.3 ? "Bearish" :
19
+ result.sentimentScore > 0 ? "Leaning Bullish" :
20
+ result.sentimentScore < 0 ? "Leaning Bearish" : "Neutral";
21
+ const lines = [
22
+ `**r/${result.subreddit}** — ${result.postCount} hot posts (${result.fetchedAt})`,
23
+ `Sentiment Score: ${result.sentimentScore.toFixed(2)} (${sentimentLabel}) | Bullish: ${result.bullishCount} | Bearish: ${result.bearishCount}`,
24
+ ];
25
+ if (result.topMentions.length > 0) {
26
+ lines.push(`Ticker mentions: ${result.topMentions.map((t) => `$${t}`).join(", ")}`);
27
+ }
28
+ lines.push("");
29
+ lines.push("Top posts:");
30
+ const top = result.posts.slice(0, 10);
31
+ for (const post of top) {
32
+ lines.push(` ⬆${post.score} 💬${post.comments} — ${post.title.slice(0, 100)}`);
33
+ }
34
+ return { content: [{ type: "text", text: lines.join("\n") }], details: result };
35
+ },
36
+ };
37
+ //# sourceMappingURL=reddit-sentiment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reddit-sentiment.js","sourceRoot":"","sources":["../../../src/tools/sentiment/reddit-sentiment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACzB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;QACrB,WAAW,EACT,kFAAkF;KACrF,CAAC;IACF,KAAK,EAAE,IAAI,CAAC,QAAQ,CAClB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC,CAChF;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAoD;IAClF,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,qKAAqK;IACvK,UAAU,EAAE,MAAM;IAClB,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAE9D,MAAM,cAAc,GAClB,MAAM,CAAC,cAAc,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YACzC,MAAM,CAAC,cAAc,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;gBAC1C,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;oBAC/C,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC;QAE5D,MAAM,KAAK,GAAG;YACZ,OAAO,MAAM,CAAC,SAAS,QAAQ,MAAM,CAAC,SAAS,eAAe,MAAM,CAAC,SAAS,GAAG;YACjF,oBAAoB,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,cAAc,gBAAgB,MAAM,CAAC,YAAY,eAAe,MAAM,CAAC,YAAY,EAAE;SAC/I,CAAC;QAEF,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,oBAAoB,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtF,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CACR,MAAM,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CACpE,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClF,CAAC;CACF,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import type { OHLCV } from "../../types/market.js";
3
+ export type Strategy = "sma_crossover" | "rsi_mean_reversion";
4
+ export interface BacktestResult {
5
+ strategy: string;
6
+ totalReturn: number;
7
+ buyAndHoldReturn: number;
8
+ trades: number;
9
+ wins: number;
10
+ winRate: number;
11
+ maxDrawdown: number;
12
+ tradeLog: Array<{
13
+ type: "buy" | "sell";
14
+ date: string;
15
+ price: number;
16
+ pnl?: number;
17
+ }>;
18
+ }
19
+ export declare function runBacktest(bars: OHLCV[], strategy: Strategy): BacktestResult;
20
+ declare const params: import("@sinclair/typebox").TObject<{
21
+ symbol: import("@sinclair/typebox").TString;
22
+ strategy: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"sma_crossover">, import("@sinclair/typebox").TLiteral<"rsi_mean_reversion">]>;
23
+ period: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
24
+ }>;
25
+ export declare const backtestTool: AgentTool<typeof params>;
26
+ export {};
@@ -0,0 +1,190 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { getHistory } from "../../providers/yahoo-finance.js";
3
+ import { computeSMA, computeRSI } from "./indicators.js";
4
+ export function runBacktest(bars, strategy) {
5
+ const closes = bars.map((b) => b.close);
6
+ const buyAndHoldReturn = closes.length > 1
7
+ ? (closes[closes.length - 1] - closes[0]) / closes[0]
8
+ : 0;
9
+ if (strategy === "sma_crossover") {
10
+ return backtestSMACrossover(bars, closes);
11
+ }
12
+ return backtestRSIMeanReversion(bars, closes);
13
+ }
14
+ function backtestSMACrossover(bars, closes) {
15
+ const sma20 = computeSMA(closes, 20);
16
+ const sma50 = computeSMA(closes, 50);
17
+ if (sma50.length === 0) {
18
+ return emptyResult("sma_crossover", closes);
19
+ }
20
+ // Align: SMA(20) starts at index 19, SMA(50) at index 49
21
+ // sma20[i] corresponds to closes[i + 19], sma50[i] to closes[i + 49]
22
+ const offset20 = 19;
23
+ const offset50 = 49;
24
+ let position = false;
25
+ let entryPrice = 0;
26
+ const tradeLog = [];
27
+ let equity = 1.0;
28
+ let peak = 1.0;
29
+ let maxDd = 0;
30
+ for (let i = 0; i < sma50.length; i++) {
31
+ const barIdx = i + offset50;
32
+ const sma20Idx = i + (offset50 - offset20);
33
+ const s20 = sma20[sma20Idx];
34
+ const s50 = sma50[i];
35
+ const price = closes[barIdx];
36
+ if (!position && s20 > s50) {
37
+ // Buy signal
38
+ position = true;
39
+ entryPrice = price;
40
+ tradeLog.push({ type: "buy", date: bars[barIdx].date, price });
41
+ }
42
+ else if (position && s20 < s50) {
43
+ // Sell signal
44
+ const pnl = (price - entryPrice) / entryPrice;
45
+ equity *= 1 + pnl;
46
+ tradeLog.push({ type: "sell", date: bars[barIdx].date, price, pnl });
47
+ position = false;
48
+ }
49
+ // Track mark-to-market equity for accurate drawdown
50
+ const currentEquity = position
51
+ ? equity * (1 + (price - entryPrice) / entryPrice)
52
+ : equity;
53
+ if (currentEquity > peak)
54
+ peak = currentEquity;
55
+ const dd = (peak - currentEquity) / peak;
56
+ if (dd > maxDd)
57
+ maxDd = dd;
58
+ }
59
+ // Close open position at end
60
+ if (position) {
61
+ const lastPrice = closes[closes.length - 1];
62
+ const pnl = (lastPrice - entryPrice) / entryPrice;
63
+ equity *= 1 + pnl;
64
+ tradeLog.push({ type: "sell", date: bars[bars.length - 1].date, price: lastPrice, pnl });
65
+ }
66
+ return buildResult("sma_crossover", equity - 1, closes, tradeLog, maxDd);
67
+ }
68
+ function backtestRSIMeanReversion(bars, closes) {
69
+ const rsi = computeRSI(closes, 14);
70
+ if (rsi.length === 0) {
71
+ return emptyResult("rsi_mean_reversion", closes);
72
+ }
73
+ // RSI starts at index 14 (after 14 periods of data)
74
+ const rsiOffset = 14;
75
+ let position = false;
76
+ let entryPrice = 0;
77
+ const tradeLog = [];
78
+ let equity = 1.0;
79
+ let peak = 1.0;
80
+ let maxDd = 0;
81
+ for (let i = 0; i < rsi.length; i++) {
82
+ const barIdx = i + rsiOffset;
83
+ const r = rsi[i];
84
+ const price = closes[barIdx];
85
+ if (!position && r < 30) {
86
+ // RSI oversold → buy
87
+ position = true;
88
+ entryPrice = price;
89
+ tradeLog.push({ type: "buy", date: bars[barIdx].date, price });
90
+ }
91
+ else if (position && r > 70) {
92
+ // RSI overbought → sell
93
+ const pnl = (price - entryPrice) / entryPrice;
94
+ equity *= 1 + pnl;
95
+ tradeLog.push({ type: "sell", date: bars[barIdx].date, price, pnl });
96
+ position = false;
97
+ }
98
+ // Track mark-to-market equity for accurate drawdown
99
+ const currentEquity = position
100
+ ? equity * (1 + (price - entryPrice) / entryPrice)
101
+ : equity;
102
+ if (currentEquity > peak)
103
+ peak = currentEquity;
104
+ const dd = (peak - currentEquity) / peak;
105
+ if (dd > maxDd)
106
+ maxDd = dd;
107
+ }
108
+ // Close open position at end
109
+ if (position) {
110
+ const lastPrice = closes[closes.length - 1];
111
+ const pnl = (lastPrice - entryPrice) / entryPrice;
112
+ equity *= 1 + pnl;
113
+ tradeLog.push({ type: "sell", date: bars[bars.length - 1].date, price: lastPrice, pnl });
114
+ }
115
+ return buildResult("rsi_mean_reversion", equity - 1, closes, tradeLog, maxDd);
116
+ }
117
+ function buildResult(strategy, totalReturn, closes, tradeLog, maxDrawdown) {
118
+ const sellTrades = tradeLog.filter((t) => t.type === "sell" && t.pnl != null);
119
+ const wins = sellTrades.filter((t) => t.pnl > 0).length;
120
+ const buyAndHoldReturn = closes.length > 1
121
+ ? (closes[closes.length - 1] - closes[0]) / closes[0]
122
+ : 0;
123
+ return {
124
+ strategy,
125
+ totalReturn,
126
+ buyAndHoldReturn,
127
+ trades: sellTrades.length,
128
+ wins,
129
+ winRate: sellTrades.length > 0 ? wins / sellTrades.length : 0,
130
+ maxDrawdown,
131
+ tradeLog,
132
+ };
133
+ }
134
+ function emptyResult(strategy, closes) {
135
+ return {
136
+ strategy,
137
+ totalReturn: 0,
138
+ buyAndHoldReturn: closes.length > 1
139
+ ? (closes[closes.length - 1] - closes[0]) / closes[0]
140
+ : 0,
141
+ trades: 0,
142
+ wins: 0,
143
+ winRate: 0,
144
+ maxDrawdown: 0,
145
+ tradeLog: [],
146
+ };
147
+ }
148
+ const params = Type.Object({
149
+ symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT, SPY)" }),
150
+ strategy: Type.Union([Type.Literal("sma_crossover"), Type.Literal("rsi_mean_reversion")], { description: "Strategy: sma_crossover (buy when SMA20 > SMA50, sell on reverse) or rsi_mean_reversion (buy when RSI < 30, sell when RSI > 70)" }),
151
+ period: Type.Optional(Type.String({ description: "Historical period to backtest: 1y, 2y, 5y. Default: 2y" })),
152
+ });
153
+ export const backtestTool = {
154
+ name: "backtest_strategy",
155
+ label: "Backtest Strategy",
156
+ description: "Backtest a simple trading strategy against historical data. Supported strategies: SMA crossover (SMA20/SMA50) and RSI mean-reversion (buy <30, sell >70). Returns total return, win rate, max drawdown, and comparison to buy-and-hold.",
157
+ parameters: params,
158
+ async execute(toolCallId, args) {
159
+ const symbol = args.symbol.toUpperCase();
160
+ const period = args.period ?? "2y";
161
+ const bars = await getHistory(symbol, period, "1d");
162
+ if (bars.length < 60) {
163
+ return {
164
+ content: [{ type: "text", text: `Insufficient data for backtesting ${symbol} (need 60+ days, got ${bars.length})` }],
165
+ details: null,
166
+ };
167
+ }
168
+ const result = runBacktest(bars, args.strategy);
169
+ const outperformance = result.totalReturn - result.buyAndHoldReturn;
170
+ const lines = [
171
+ `**${symbol} Backtest: ${args.strategy}** (${bars[0].date} to ${bars[bars.length - 1].date}, ${bars.length} days)`,
172
+ ``,
173
+ `Strategy Return: ${(result.totalReturn * 100).toFixed(2)}%`,
174
+ `Buy & Hold Return: ${(result.buyAndHoldReturn * 100).toFixed(2)}%`,
175
+ `Outperformance: ${outperformance >= 0 ? "+" : ""}${(outperformance * 100).toFixed(2)}%`,
176
+ ``,
177
+ `Trades: ${result.trades} | Wins: ${result.wins} | Win Rate: ${(result.winRate * 100).toFixed(0)}%`,
178
+ `Max Drawdown: ${(result.maxDrawdown * 100).toFixed(2)}%`,
179
+ ``,
180
+ result.totalReturn > result.buyAndHoldReturn
181
+ ? `Strategy outperformed buy-and-hold by ${(outperformance * 100).toFixed(2)}%.`
182
+ : `Buy-and-hold outperformed the strategy by ${(-outperformance * 100).toFixed(2)}%.`,
183
+ ];
184
+ return {
185
+ content: [{ type: "text", text: lines.join("\n") }],
186
+ details: result,
187
+ };
188
+ },
189
+ };
190
+ //# sourceMappingURL=backtest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backtest.js","sourceRoot":"","sources":["../../../src/tools/technical/backtest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAgBzD,MAAM,UAAU,WAAW,CAAC,IAAa,EAAE,QAAkB;IAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC;QACxC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC,CAAC;IAEN,IAAI,QAAQ,KAAK,eAAe,EAAE,CAAC;QACjC,OAAO,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,wBAAwB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAa,EAAE,MAAgB;IAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAErC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,WAAW,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IAED,yDAAyD;IACzD,qEAAqE;IACrE,MAAM,QAAQ,GAAG,EAAE,CAAC;IACpB,MAAM,QAAQ,GAAG,EAAE,CAAC;IAEpB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,QAAQ,GAA+B,EAAE,CAAC;IAChD,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,IAAI,IAAI,GAAG,GAAG,CAAC;IACf,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC;QAC5B,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAE7B,IAAI,CAAC,QAAQ,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;YAC3B,aAAa;YACb,QAAQ,GAAG,IAAI,CAAC;YAChB,UAAU,GAAG,KAAK,CAAC;YACnB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjE,CAAC;aAAM,IAAI,QAAQ,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;YACjC,cAAc;YACd,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;YAC9C,MAAM,IAAI,CAAC,GAAG,GAAG,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YACrE,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;QAED,oDAAoD;QACpD,MAAM,aAAa,GAAG,QAAQ;YAC5B,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;YAClD,CAAC,CAAC,MAAM,CAAC;QACX,IAAI,aAAa,GAAG,IAAI;YAAE,IAAI,GAAG,aAAa,CAAC;QAC/C,MAAM,EAAE,GAAG,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,IAAI,CAAC;QACzC,IAAI,EAAE,GAAG,KAAK;YAAE,KAAK,GAAG,EAAE,CAAC;IAC7B,CAAC;IAED,6BAA6B;IAC7B,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;QAClD,MAAM,IAAI,CAAC,GAAG,GAAG,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,OAAO,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,wBAAwB,CAAC,IAAa,EAAE,MAAgB;IAC/D,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAEnC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,WAAW,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IAED,oDAAoD;IACpD,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,QAAQ,GAA+B,EAAE,CAAC;IAChD,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,IAAI,IAAI,GAAG,GAAG,CAAC;IACf,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;QAC7B,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACjB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAE7B,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACxB,qBAAqB;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,UAAU,GAAG,KAAK,CAAC;YACnB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjE,CAAC;aAAM,IAAI,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAC9B,wBAAwB;YACxB,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;YAC9C,MAAM,IAAI,CAAC,GAAG,GAAG,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YACrE,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;QAED,oDAAoD;QACpD,MAAM,aAAa,GAAG,QAAQ;YAC5B,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;YAClD,CAAC,CAAC,MAAM,CAAC;QACX,IAAI,aAAa,GAAG,IAAI;YAAE,IAAI,GAAG,aAAa,CAAC;QAC/C,MAAM,EAAE,GAAG,CAAC,IAAI,GAAG,aAAa,CAAC,GAAG,IAAI,CAAC;QACzC,IAAI,EAAE,GAAG,KAAK;YAAE,KAAK,GAAG,EAAE,CAAC;IAC7B,CAAC;IAED,6BAA6B;IAC7B,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;QAClD,MAAM,IAAI,CAAC,GAAG,GAAG,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,OAAO,WAAW,CAAC,oBAAoB,EAAE,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,WAAW,CAClB,QAAgB,EAChB,WAAmB,EACnB,MAAgB,EAChB,QAAoC,EACpC,WAAmB;IAEnB,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC;QACxC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC,CAAC;IAEN,OAAO;QACL,QAAQ;QACR,WAAW;QACX,gBAAgB;QAChB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,IAAI;QACJ,OAAO,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7D,WAAW;QACX,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,QAAgB,EAAE,MAAgB;IACrD,OAAO;QACL,QAAQ;QACR,WAAW,EAAE,CAAC;QACd,gBAAgB,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC;YACjC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,MAAM,EAAE,CAAC;QACT,IAAI,EAAE,CAAC;QACP,OAAO,EAAE,CAAC;QACV,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACzB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,4CAA4C,EAAE,CAAC;IAClF,QAAQ,EAAE,IAAI,CAAC,KAAK,CAClB,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,EACnE,EAAE,WAAW,EAAE,iIAAiI,EAAE,CACnJ;IACD,MAAM,EAAE,IAAI,CAAC,QAAQ,CACnB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,wDAAwD,EAAE,CAAC,CACvF;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAA6B;IACpD,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EACT,yOAAyO;IAC3O,UAAU,EAAE,MAAM;IAClB,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;QACnC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QAEpD,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACrB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qCAAqC,MAAM,wBAAwB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;gBACpH,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEhD,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACpE,MAAM,KAAK,GAAG;YACZ,KAAK,MAAM,cAAc,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,QAAQ;YAClH,EAAE;YACF,oBAAoB,CAAC,MAAM,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;YAC5D,sBAAsB,CAAC,MAAM,CAAC,gBAAgB,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;YACnE,mBAAmB,cAAc,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,cAAc,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;YACxF,EAAE;YACF,WAAW,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,IAAI,gBAAgB,CAAC,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;YACnG,iBAAiB,CAAC,MAAM,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;YACzD,EAAE;YACF,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,gBAAgB;gBAC1C,CAAC,CAAC,yCAAyC,CAAC,cAAc,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;gBAChF,CAAC,CAAC,6CAA6C,CAAC,CAAC,cAAc,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;SACxF,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,EAAE,MAAM;SAChB,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import type { OHLCV } from "../../types/market.js";
3
+ export declare function computeOBV(bars: OHLCV[]): number[];
4
+ export declare function computeVWAP(bars: OHLCV[]): number[];
5
+ declare const params: import("@sinclair/typebox").TObject<{
6
+ symbol: import("@sinclair/typebox").TString;
7
+ range: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
8
+ }>;
9
+ export declare const technicalIndicatorsTool: AgentTool<typeof params>;
10
+ export declare function computeSMA(data: number[], period: number): number[];
11
+ export declare function computeEMA(data: number[], period: number): number[];
12
+ export declare function computeRSI(data: number[], period?: number): number[];
13
+ export declare function computeMACD(data: number[], fastPeriod?: number, slowPeriod?: number, signalPeriod?: number): {
14
+ macd: number;
15
+ signal: number;
16
+ histogram: number;
17
+ }[];
18
+ export declare function computeBollingerBands(data: number[], period?: number, stdDev?: number): {
19
+ upper: number;
20
+ middle: number;
21
+ lower: number;
22
+ }[];
23
+ export {};
@@ -0,0 +1,212 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { getHistory } from "../../providers/yahoo-finance.js";
3
+ // --- Volume-based indicators ---
4
+ export function computeOBV(bars) {
5
+ const obv = [0];
6
+ for (let i = 1; i < bars.length; i++) {
7
+ if (bars[i].close > bars[i - 1].close) {
8
+ obv.push(obv[i - 1] + bars[i].volume);
9
+ }
10
+ else if (bars[i].close < bars[i - 1].close) {
11
+ obv.push(obv[i - 1] - bars[i].volume);
12
+ }
13
+ else {
14
+ obv.push(obv[i - 1]);
15
+ }
16
+ }
17
+ return obv;
18
+ }
19
+ export function computeVWAP(bars) {
20
+ const vwap = [];
21
+ let cumPV = 0;
22
+ let cumVol = 0;
23
+ for (const bar of bars) {
24
+ const tp = (bar.high + bar.low + bar.close) / 3;
25
+ cumPV += tp * bar.volume;
26
+ cumVol += bar.volume;
27
+ vwap.push(cumVol === 0 ? 0 : cumPV / cumVol);
28
+ }
29
+ return vwap;
30
+ }
31
+ const params = Type.Object({
32
+ symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT)" }),
33
+ range: Type.Optional(Type.String({ description: "Time range for data: 3mo, 6mo, 1y, 2y. Default: 1y" })),
34
+ });
35
+ export const technicalIndicatorsTool = {
36
+ name: "get_technical_indicators",
37
+ label: "Technical Indicators",
38
+ description: "Compute technical indicators (SMA, EMA, RSI, MACD, Bollinger Bands) from historical price data. All computed locally — no API dependency.",
39
+ parameters: params,
40
+ async execute(toolCallId, args) {
41
+ const symbol = args.symbol.toUpperCase();
42
+ const range = args.range ?? "1y";
43
+ const bars = await getHistory(symbol, range, "1d");
44
+ const closes = bars.map((b) => b.close);
45
+ if (closes.length < 26) {
46
+ return {
47
+ content: [{ type: "text", text: `Insufficient data for ${symbol} (need 26+ bars, got ${closes.length})` }],
48
+ details: null,
49
+ };
50
+ }
51
+ const sma20 = computeSMA(closes, 20);
52
+ const sma50 = computeSMA(closes, 50);
53
+ const ema12 = computeEMA(closes, 12);
54
+ const ema26 = computeEMA(closes, 26);
55
+ const rsi = computeRSI(closes, 14);
56
+ const macd = computeMACD(closes);
57
+ const bb = computeBollingerBands(closes, 20, 2);
58
+ const obv = computeOBV(bars);
59
+ const vwap = computeVWAP(bars);
60
+ const latest = closes[closes.length - 1];
61
+ const latestRsi = rsi[rsi.length - 1];
62
+ const latestMacd = macd[macd.length - 1];
63
+ const latestBB = bb[bb.length - 1];
64
+ const latestVwap = vwap[vwap.length - 1];
65
+ const obvTrend = obv.length >= 20
66
+ ? (obv[obv.length - 1] > obv[obv.length - 20] ? "Rising" : "Falling")
67
+ : "N/A";
68
+ const lines = [
69
+ `**${symbol} Technical Analysis** (${bars[0].date} to ${bars[bars.length - 1].date})`,
70
+ `Price: $${latest.toFixed(2)}`,
71
+ ``,
72
+ `SMA(20): $${sma20[sma20.length - 1]?.toFixed(2) ?? "N/A"} | SMA(50): $${sma50[sma50.length - 1]?.toFixed(2) ?? "N/A"}`,
73
+ `RSI(14): ${latestRsi?.toFixed(1) ?? "N/A"} ${rsiSignal(latestRsi)}`,
74
+ `MACD: ${latestMacd?.macd.toFixed(2) ?? "N/A"} | Signal: ${latestMacd?.signal.toFixed(2) ?? "N/A"} | Histogram: ${latestMacd?.histogram.toFixed(2) ?? "N/A"}`,
75
+ `Bollinger Bands: Upper $${latestBB?.upper.toFixed(2) ?? "N/A"} | Mid $${latestBB?.middle.toFixed(2) ?? "N/A"} | Lower $${latestBB?.lower.toFixed(2) ?? "N/A"}`,
76
+ `OBV Trend: ${obvTrend} | VWAP (cumulative): $${latestVwap?.toFixed(2) ?? "N/A"}`,
77
+ ``,
78
+ trendSummary(latest, sma20, sma50, latestRsi, latestMacd, obvTrend, latestVwap),
79
+ ];
80
+ return {
81
+ content: [{ type: "text", text: lines.join("\n") }],
82
+ details: { sma20, sma50, rsi, macd, bb, obv, vwap },
83
+ };
84
+ },
85
+ };
86
+ // --- Indicator computations (all pure functions) ---
87
+ export function computeSMA(data, period) {
88
+ const result = [];
89
+ for (let i = period - 1; i < data.length; i++) {
90
+ let sum = 0;
91
+ for (let j = i - period + 1; j <= i; j++)
92
+ sum += data[j];
93
+ result.push(sum / period);
94
+ }
95
+ return result;
96
+ }
97
+ export function computeEMA(data, period) {
98
+ const k = 2 / (period + 1);
99
+ const result = [];
100
+ // Seed with SMA of first `period` values
101
+ let sum = 0;
102
+ for (let i = 0; i < period; i++)
103
+ sum += data[i];
104
+ let ema = sum / period;
105
+ result.push(ema);
106
+ for (let i = period; i < data.length; i++) {
107
+ ema = data[i] * k + ema * (1 - k);
108
+ result.push(ema);
109
+ }
110
+ return result;
111
+ }
112
+ export function computeRSI(data, period = 14) {
113
+ const result = [];
114
+ const gains = [];
115
+ const losses = [];
116
+ for (let i = 1; i < data.length; i++) {
117
+ const diff = data[i] - data[i - 1];
118
+ gains.push(diff > 0 ? diff : 0);
119
+ losses.push(diff < 0 ? -diff : 0);
120
+ }
121
+ if (gains.length < period)
122
+ return result;
123
+ let avgGain = gains.slice(0, period).reduce((a, b) => a + b, 0) / period;
124
+ let avgLoss = losses.slice(0, period).reduce((a, b) => a + b, 0) / period;
125
+ const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;
126
+ result.push(100 - 100 / (1 + rs));
127
+ for (let i = period; i < gains.length; i++) {
128
+ avgGain = (avgGain * (period - 1) + gains[i]) / period;
129
+ avgLoss = (avgLoss * (period - 1) + losses[i]) / period;
130
+ const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;
131
+ result.push(100 - 100 / (1 + rs));
132
+ }
133
+ return result;
134
+ }
135
+ export function computeMACD(data, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) {
136
+ if (data.length < slowPeriod + signalPeriod)
137
+ return [];
138
+ const emaFast = computeEMA(data, fastPeriod);
139
+ const emaSlow = computeEMA(data, slowPeriod);
140
+ // Align: emaFast starts at index fastPeriod-1, emaSlow at slowPeriod-1
141
+ const offset = slowPeriod - fastPeriod;
142
+ const macdLine = [];
143
+ for (let i = 0; i < emaSlow.length; i++) {
144
+ macdLine.push(emaFast[i + offset] - emaSlow[i]);
145
+ }
146
+ if (macdLine.length < signalPeriod)
147
+ return [];
148
+ const signalLine = computeEMA(macdLine, signalPeriod);
149
+ const signalOffset = signalPeriod - 1;
150
+ const result = [];
151
+ for (let i = 0; i < signalLine.length; i++) {
152
+ const m = macdLine[i + signalOffset];
153
+ const s = signalLine[i];
154
+ result.push({ macd: m, signal: s, histogram: m - s });
155
+ }
156
+ return result;
157
+ }
158
+ export function computeBollingerBands(data, period = 20, stdDev = 2) {
159
+ const result = [];
160
+ for (let i = period - 1; i < data.length; i++) {
161
+ const slice = data.slice(i - period + 1, i + 1);
162
+ const mean = slice.reduce((a, b) => a + b, 0) / period;
163
+ const variance = slice.reduce((a, b) => a + (b - mean) ** 2, 0) / period;
164
+ const sd = Math.sqrt(variance);
165
+ result.push({
166
+ upper: mean + stdDev * sd,
167
+ middle: mean,
168
+ lower: mean - stdDev * sd,
169
+ });
170
+ }
171
+ return result;
172
+ }
173
+ function rsiSignal(rsi) {
174
+ if (rsi == null)
175
+ return "";
176
+ if (rsi >= 70)
177
+ return "(Overbought)";
178
+ if (rsi <= 30)
179
+ return "(Oversold)";
180
+ return "(Neutral)";
181
+ }
182
+ function trendSummary(price, sma20, sma50, rsi, macd, obvTrend, vwap) {
183
+ const signals = [];
184
+ const latestSma20 = sma20[sma20.length - 1];
185
+ const latestSma50 = sma50[sma50.length - 1];
186
+ if (latestSma20 && price > latestSma20)
187
+ signals.push("Price above SMA(20) — short-term bullish");
188
+ if (latestSma20 && price < latestSma20)
189
+ signals.push("Price below SMA(20) — short-term bearish");
190
+ if (latestSma20 && latestSma50 && latestSma20 > latestSma50)
191
+ signals.push("Golden cross pattern (SMA20 > SMA50)");
192
+ if (latestSma20 && latestSma50 && latestSma20 < latestSma50)
193
+ signals.push("Death cross pattern (SMA20 < SMA50)");
194
+ if (rsi != null && rsi >= 70)
195
+ signals.push("RSI overbought — potential reversal");
196
+ if (rsi != null && rsi <= 30)
197
+ signals.push("RSI oversold — potential bounce");
198
+ if (macd && macd.histogram > 0)
199
+ signals.push("MACD bullish (histogram positive)");
200
+ if (macd && macd.histogram < 0)
201
+ signals.push("MACD bearish (histogram negative)");
202
+ if (obvTrend === "Rising" && price > (latestSma20 ?? 0))
203
+ signals.push("Volume confirming price advance (OBV rising)");
204
+ if (obvTrend === "Falling" && price < (latestSma20 ?? Infinity))
205
+ signals.push("Volume confirming price decline (OBV falling)");
206
+ if (vwap != null && price > vwap)
207
+ signals.push("Price above cumulative VWAP — bullish volume-weighted bias");
208
+ if (vwap != null && price < vwap)
209
+ signals.push("Price below cumulative VWAP — bearish volume-weighted bias");
210
+ return signals.length > 0 ? "Signals: " + signals.join(" | ") : "No strong signals";
211
+ }
212
+ //# sourceMappingURL=indicators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indicators.js","sourceRoot":"","sources":["../../../src/tools/technical/indicators.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ export interface CompanyOverview {
2
+ symbol: string;
3
+ name: string;
4
+ description: string;
5
+ exchange: string;
6
+ sector: string;
7
+ industry: string;
8
+ marketCap: number;
9
+ pe: number | null;
10
+ forwardPe: number | null;
11
+ eps: number | null;
12
+ dividendYield: number | null;
13
+ beta: number | null;
14
+ week52High: number;
15
+ week52Low: number;
16
+ avgVolume: number;
17
+ profitMargin: number | null;
18
+ revenueGrowth: number | null;
19
+ }
20
+ export interface EarningsData {
21
+ symbol: string;
22
+ quarterly: Array<{
23
+ date: string;
24
+ reportedEPS: number;
25
+ estimatedEPS: number;
26
+ surprise: number;
27
+ surprisePercent: number;
28
+ }>;
29
+ }
30
+ export interface FinancialStatement {
31
+ fiscalDate: string;
32
+ revenue: number;
33
+ grossProfit: number;
34
+ operatingIncome: number;
35
+ netIncome: number;
36
+ eps: number;
37
+ totalAssets: number;
38
+ totalLiabilities: number;
39
+ totalEquity: number;
40
+ operatingCashFlow: number;
41
+ freeCashFlow: number;
42
+ totalDebt?: number;
43
+ cashAndEquivalents?: number;
44
+ }