opencandle 0.4.0 → 0.6.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.
- package/LICENSE +1 -1
- package/README.md +186 -117
- package/dist/analysts/contracts.d.ts +1 -3
- package/dist/analysts/contracts.js +1 -11
- package/dist/analysts/contracts.js.map +1 -1
- package/dist/analysts/orchestrator.d.ts +1 -3
- package/dist/analysts/orchestrator.js +1 -26
- package/dist/analysts/orchestrator.js.map +1 -1
- package/dist/cli.js +32 -8
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +19 -3
- package/dist/config.js +69 -3
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infra/browser.d.ts +1 -3
- package/dist/infra/browser.js +4 -2
- package/dist/infra/browser.js.map +1 -1
- package/dist/infra/cache.d.ts +8 -11
- package/dist/infra/cache.js +17 -15
- package/dist/infra/cache.js.map +1 -1
- package/dist/infra/http-client.d.ts +4 -1
- package/dist/infra/http-client.js +59 -6
- package/dist/infra/http-client.js.map +1 -1
- package/dist/infra/index.d.ts +3 -3
- package/dist/infra/index.js +3 -3
- package/dist/infra/index.js.map +1 -1
- package/dist/infra/native-dependencies.js +2 -2
- package/dist/infra/native-dependencies.js.map +1 -1
- package/dist/infra/node-version.js.map +1 -1
- package/dist/infra/opencandle-paths.d.ts +0 -3
- package/dist/infra/opencandle-paths.js +4 -11
- package/dist/infra/opencandle-paths.js.map +1 -1
- package/dist/infra/rate-limiter.d.ts +4 -0
- package/dist/infra/rate-limiter.js +17 -10
- package/dist/infra/rate-limiter.js.map +1 -1
- package/dist/market-state/alert-conditions.d.ts +34 -0
- package/dist/market-state/alert-conditions.js +23 -0
- package/dist/market-state/alert-conditions.js.map +1 -0
- package/dist/market-state/alert-runner.d.ts +55 -0
- package/dist/market-state/alert-runner.js +634 -0
- package/dist/market-state/alert-runner.js.map +1 -0
- package/dist/market-state/daily-report.d.ts +26 -0
- package/dist/market-state/daily-report.js +179 -0
- package/dist/market-state/daily-report.js.map +1 -0
- package/dist/market-state/local-automation-service.d.ts +25 -0
- package/dist/market-state/local-automation-service.js +119 -0
- package/dist/market-state/local-automation-service.js.map +1 -0
- package/dist/market-state/notification-delivery.d.ts +14 -0
- package/dist/market-state/notification-delivery.js +139 -0
- package/dist/market-state/notification-delivery.js.map +1 -0
- package/dist/market-state/resolve-for-mutation.d.ts +10 -0
- package/dist/market-state/resolve-for-mutation.js +15 -0
- package/dist/market-state/resolve-for-mutation.js.map +1 -0
- package/dist/market-state/resolve.d.ts +14 -0
- package/dist/market-state/resolve.js +89 -0
- package/dist/market-state/resolve.js.map +1 -0
- package/dist/market-state/service.d.ts +527 -0
- package/dist/market-state/service.js +1099 -0
- package/dist/market-state/service.js.map +1 -0
- package/dist/memory/index.d.ts +7 -7
- package/dist/memory/index.js +6 -6
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/manager.d.ts +9 -0
- package/dist/memory/manager.js +39 -22
- package/dist/memory/manager.js.map +1 -1
- package/dist/memory/retrieval.js +7 -4
- package/dist/memory/retrieval.js.map +1 -1
- package/dist/memory/sqlite.js +385 -3
- package/dist/memory/sqlite.js.map +1 -1
- package/dist/memory/storage.d.ts +3 -2
- package/dist/memory/storage.js +1 -2
- package/dist/memory/storage.js.map +1 -1
- package/dist/memory/tool-defaults.js +64 -28
- package/dist/memory/tool-defaults.js.map +1 -1
- package/dist/memory/types.js +4 -0
- package/dist/memory/types.js.map +1 -1
- package/dist/monitor.d.ts +2 -0
- package/dist/monitor.js +104 -0
- package/dist/monitor.js.map +1 -0
- package/dist/onboarding/connect.js +4 -6
- package/dist/onboarding/connect.js.map +1 -1
- package/dist/onboarding/credential-interceptor.js +1 -1
- package/dist/onboarding/credential-interceptor.js.map +1 -1
- package/dist/onboarding/degradation-accumulator.js +1 -3
- package/dist/onboarding/degradation-accumulator.js.map +1 -1
- package/dist/onboarding/providers.js +3 -16
- package/dist/onboarding/providers.js.map +1 -1
- package/dist/onboarding/state.js.map +1 -1
- package/dist/onboarding/tool-helpers.js +1 -1
- package/dist/onboarding/tool-helpers.js.map +1 -1
- package/dist/onboarding/tool-tags.js +6 -4
- package/dist/onboarding/tool-tags.js.map +1 -1
- package/dist/onboarding/validation.js +1 -1
- package/dist/onboarding/validation.js.map +1 -1
- package/dist/pi/opencandle-extension.d.ts +8 -0
- package/dist/pi/opencandle-extension.js +637 -59
- package/dist/pi/opencandle-extension.js.map +1 -1
- package/dist/pi/session.d.ts +1 -1
- package/dist/pi/session.js +3 -1
- package/dist/pi/session.js.map +1 -1
- package/dist/pi/setup.js +17 -2
- package/dist/pi/setup.js.map +1 -1
- package/dist/pi/tool-adapter.js +5 -2
- package/dist/pi/tool-adapter.js.map +1 -1
- package/dist/prompts/context-builder.d.ts +18 -3
- package/dist/prompts/context-builder.js +117 -18
- package/dist/prompts/context-builder.js.map +1 -1
- package/dist/prompts/disclaimer.js +1 -1
- package/dist/prompts/disclaimer.js.map +1 -1
- package/dist/prompts/policy-cards.d.ts +13 -0
- package/dist/prompts/policy-cards.js +197 -0
- package/dist/prompts/policy-cards.js.map +1 -0
- package/dist/prompts/sections.d.ts +1 -1
- package/dist/prompts/sections.js +3 -3
- package/dist/prompts/sections.js.map +1 -1
- package/dist/prompts/symbol-preflight.d.ts +20 -0
- package/dist/prompts/symbol-preflight.js +49 -0
- package/dist/prompts/symbol-preflight.js.map +1 -0
- package/dist/prompts/workflow-prompts.d.ts +1 -1
- package/dist/prompts/workflow-prompts.js +209 -19
- package/dist/prompts/workflow-prompts.js.map +1 -1
- package/dist/providers/alpha-vantage.d.ts +1 -1
- package/dist/providers/alpha-vantage.js +49 -8
- package/dist/providers/alpha-vantage.js.map +1 -1
- package/dist/providers/coingecko.js +1 -1
- package/dist/providers/coingecko.js.map +1 -1
- package/dist/providers/errors.d.ts +5 -0
- package/dist/providers/errors.js +11 -0
- package/dist/providers/errors.js.map +1 -0
- package/dist/providers/exa-search.d.ts +2 -2
- package/dist/providers/exa-search.js +19 -11
- package/dist/providers/exa-search.js.map +1 -1
- package/dist/providers/fear-greed.js +1 -1
- package/dist/providers/fear-greed.js.map +1 -1
- package/dist/providers/finnhub.js +3 -5
- package/dist/providers/finnhub.js.map +1 -1
- package/dist/providers/fred.js +2 -2
- package/dist/providers/fred.js.map +1 -1
- package/dist/providers/index.d.ts +7 -6
- package/dist/providers/index.js +6 -5
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/reddit.js +2 -2
- package/dist/providers/reddit.js.map +1 -1
- package/dist/providers/sec-edgar.d.ts +9 -1
- package/dist/providers/sec-edgar.js +181 -6
- package/dist/providers/sec-edgar.js.map +1 -1
- package/dist/providers/tradingview.d.ts +47 -0
- package/dist/providers/tradingview.js +275 -0
- package/dist/providers/tradingview.js.map +1 -0
- package/dist/providers/twitter.js +6 -8
- package/dist/providers/twitter.js.map +1 -1
- package/dist/providers/web-search.js +26 -12
- package/dist/providers/web-search.js.map +1 -1
- package/dist/providers/with-fallback.js +4 -2
- package/dist/providers/with-fallback.js.map +1 -1
- package/dist/providers/wrap-provider.d.ts +2 -3
- package/dist/providers/wrap-provider.js +14 -8
- package/dist/providers/wrap-provider.js.map +1 -1
- package/dist/providers/yahoo-finance.d.ts +3 -1
- package/dist/providers/yahoo-finance.js +226 -11
- package/dist/providers/yahoo-finance.js.map +1 -1
- package/dist/routing/classify-intent.d.ts +9 -0
- package/dist/routing/classify-intent.js +153 -3
- package/dist/routing/classify-intent.js.map +1 -1
- package/dist/routing/defaults.d.ts +1 -1
- package/dist/routing/defaults.js +3 -3
- package/dist/routing/defaults.js.map +1 -1
- package/dist/routing/entity-extractor.d.ts +2 -0
- package/dist/routing/entity-extractor.js +377 -26
- package/dist/routing/entity-extractor.js.map +1 -1
- package/dist/routing/fund-symbols.d.ts +2 -0
- package/dist/routing/fund-symbols.js +55 -0
- package/dist/routing/fund-symbols.js.map +1 -0
- package/dist/routing/horizon.d.ts +1 -0
- package/dist/routing/horizon.js +10 -0
- package/dist/routing/horizon.js.map +1 -0
- package/dist/routing/index.d.ts +12 -6
- package/dist/routing/index.js +8 -4
- package/dist/routing/index.js.map +1 -1
- package/dist/routing/legacy-rule-router.d.ts +9 -0
- package/dist/routing/legacy-rule-router.js +12 -0
- package/dist/routing/legacy-rule-router.js.map +1 -0
- package/dist/routing/planning.d.ts +54 -0
- package/dist/routing/planning.js +562 -0
- package/dist/routing/planning.js.map +1 -0
- package/dist/routing/route-manifest.d.ts +35 -0
- package/dist/routing/route-manifest.js +242 -0
- package/dist/routing/route-manifest.js.map +1 -0
- package/dist/routing/router-llm-client.js.map +1 -1
- package/dist/routing/router-prompt.js +46 -45
- package/dist/routing/router-prompt.js.map +1 -1
- package/dist/routing/router-types.d.ts +10 -0
- package/dist/routing/router.d.ts +1 -0
- package/dist/routing/router.js +572 -13
- package/dist/routing/router.js.map +1 -1
- package/dist/routing/slot-resolver.d.ts +1 -1
- package/dist/routing/slot-resolver.js +45 -7
- package/dist/routing/slot-resolver.js.map +1 -1
- package/dist/routing/symbol-disambiguator.d.ts +11 -0
- package/dist/routing/symbol-disambiguator.js +52 -0
- package/dist/routing/symbol-disambiguator.js.map +1 -0
- package/dist/routing/turn-context.d.ts +44 -0
- package/dist/routing/turn-context.js +45 -0
- package/dist/routing/turn-context.js.map +1 -0
- package/dist/routing/types.d.ts +15 -1
- package/dist/runtime/answer-contracts.d.ts +82 -0
- package/dist/runtime/answer-contracts.js +442 -0
- package/dist/runtime/answer-contracts.js.map +1 -0
- package/dist/runtime/artifact-contracts.d.ts +14 -0
- package/dist/runtime/artifact-contracts.js +57 -0
- package/dist/runtime/artifact-contracts.js.map +1 -0
- package/dist/runtime/planning-evidence.d.ts +99 -0
- package/dist/runtime/planning-evidence.js +466 -0
- package/dist/runtime/planning-evidence.js.map +1 -0
- package/dist/runtime/prompt-step.d.ts +1 -9
- package/dist/runtime/prompt-step.js +0 -10
- package/dist/runtime/prompt-step.js.map +1 -1
- package/dist/runtime/run-context.d.ts +5 -2
- package/dist/runtime/run-context.js +8 -1
- package/dist/runtime/run-context.js.map +1 -1
- package/dist/runtime/session-coordinator.d.ts +29 -3
- package/dist/runtime/session-coordinator.js +204 -31
- package/dist/runtime/session-coordinator.js.map +1 -1
- package/dist/runtime/session-title.d.ts +14 -0
- package/dist/runtime/session-title.js +50 -0
- package/dist/runtime/session-title.js.map +1 -0
- package/dist/runtime/tool-defaults-wrapper.js +1 -3
- package/dist/runtime/tool-defaults-wrapper.js.map +1 -1
- package/dist/runtime/validation.js.map +1 -1
- package/dist/runtime/workflow-events.js.map +1 -1
- package/dist/runtime/workflow-runner.d.ts +3 -3
- package/dist/runtime/workflow-runner.js +1 -1
- package/dist/runtime/workflow-runner.js.map +1 -1
- package/dist/sentiment/adapters/finnhub.d.ts +1 -1
- package/dist/sentiment/adapters/finnhub.js +6 -1
- package/dist/sentiment/adapters/finnhub.js.map +1 -1
- package/dist/sentiment/adapters/reddit.d.ts +2 -2
- package/dist/sentiment/adapters/twitter.d.ts +1 -1
- package/dist/sentiment/adapters/web.d.ts +1 -1
- package/dist/sentiment/index.d.ts +9 -11
- package/dist/sentiment/index.js +9 -20
- package/dist/sentiment/index.js.map +1 -1
- package/dist/sentiment/keywords.js +26 -4
- package/dist/sentiment/keywords.js.map +1 -1
- package/dist/sentiment/pipeline.d.ts +2 -2
- package/dist/sentiment/pipeline.js +1 -1
- package/dist/sentiment/pipeline.js.map +1 -1
- package/dist/sentiment/scorer.js +1 -1
- package/dist/sentiment/store.d.ts +1 -1
- package/dist/sentiment/store.js +1 -1
- package/dist/sentiment/store.js.map +1 -1
- package/dist/sentiment/trends.d.ts +1 -1
- package/dist/sentiment/trends.js.map +1 -1
- package/dist/sentiment/types.js.map +1 -1
- package/dist/system-prompt.js +7 -3
- package/dist/system-prompt.js.map +1 -1
- package/dist/tool-kit.d.ts +7 -7
- package/dist/tool-kit.js +4 -4
- package/dist/tool-kit.js.map +1 -1
- package/dist/tools/fundamentals/company-overview.js +12 -7
- package/dist/tools/fundamentals/company-overview.js.map +1 -1
- package/dist/tools/fundamentals/comps.js +19 -10
- package/dist/tools/fundamentals/comps.js.map +1 -1
- package/dist/tools/fundamentals/dcf.js +24 -12
- package/dist/tools/fundamentals/dcf.js.map +1 -1
- package/dist/tools/fundamentals/earnings.js +9 -4
- package/dist/tools/fundamentals/earnings.js.map +1 -1
- package/dist/tools/fundamentals/financials.js +9 -4
- package/dist/tools/fundamentals/financials.js.map +1 -1
- package/dist/tools/fundamentals/sec-filings.d.ts +1 -0
- package/dist/tools/fundamentals/sec-filings.js +36 -4
- package/dist/tools/fundamentals/sec-filings.js.map +1 -1
- package/dist/tools/index.d.ts +23 -18
- package/dist/tools/index.js +53 -38
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/interaction/ask-user.js +15 -3
- package/dist/tools/interaction/ask-user.js.map +1 -1
- package/dist/tools/interaction/twitter-login.js +13 -3
- package/dist/tools/interaction/twitter-login.js.map +1 -1
- package/dist/tools/macro/fear-greed.js +1 -1
- package/dist/tools/macro/fear-greed.js.map +1 -1
- package/dist/tools/macro/fred-data.d.ts +1 -1
- package/dist/tools/macro/fred-data.js +44 -9
- package/dist/tools/macro/fred-data.js.map +1 -1
- package/dist/tools/market/crypto-history.js +21 -3
- package/dist/tools/market/crypto-history.js.map +1 -1
- package/dist/tools/market/crypto-price.js +4 -2
- package/dist/tools/market/crypto-price.js.map +1 -1
- package/dist/tools/market/screen-stocks.d.ts +18 -0
- package/dist/tools/market/screen-stocks.js +252 -0
- package/dist/tools/market/screen-stocks.js.map +1 -0
- package/dist/tools/market/search-ticker.js +161 -9
- package/dist/tools/market/search-ticker.js.map +1 -1
- package/dist/tools/market/stock-history.d.ts +2 -2
- package/dist/tools/market/stock-history.js +27 -8
- package/dist/tools/market/stock-history.js.map +1 -1
- package/dist/tools/market/stock-quote.js +6 -4
- package/dist/tools/market/stock-quote.js.map +1 -1
- package/dist/tools/options/greeks.js +1 -2
- package/dist/tools/options/greeks.js.map +1 -1
- package/dist/tools/options/option-chain.js +27 -9
- package/dist/tools/options/option-chain.js.map +1 -1
- package/dist/tools/portfolio/alerts.d.ts +15 -0
- package/dist/tools/portfolio/alerts.js +357 -0
- package/dist/tools/portfolio/alerts.js.map +1 -0
- package/dist/tools/portfolio/correlation.d.ts +1 -1
- package/dist/tools/portfolio/correlation.js +34 -14
- package/dist/tools/portfolio/correlation.js.map +1 -1
- package/dist/tools/portfolio/daily-report.d.ts +8 -0
- package/dist/tools/portfolio/daily-report.js +83 -0
- package/dist/tools/portfolio/daily-report.js.map +1 -0
- package/dist/tools/portfolio/holdings-overlap.d.ts +8 -0
- package/dist/tools/portfolio/holdings-overlap.js +112 -0
- package/dist/tools/portfolio/holdings-overlap.js.map +1 -0
- package/dist/tools/portfolio/notifications.d.ts +7 -0
- package/dist/tools/portfolio/notifications.js +43 -0
- package/dist/tools/portfolio/notifications.js.map +1 -0
- package/dist/tools/portfolio/predictions.d.ts +12 -6
- package/dist/tools/portfolio/predictions.js +338 -88
- package/dist/tools/portfolio/predictions.js.map +1 -1
- package/dist/tools/portfolio/risk-analysis.d.ts +1 -1
- package/dist/tools/portfolio/risk-analysis.js +46 -7
- package/dist/tools/portfolio/risk-analysis.js.map +1 -1
- package/dist/tools/portfolio/tracker.d.ts +4 -3
- package/dist/tools/portfolio/tracker.js +247 -102
- package/dist/tools/portfolio/tracker.js.map +1 -1
- package/dist/tools/portfolio/watchlist.d.ts +6 -4
- package/dist/tools/portfolio/watchlist.js +209 -101
- package/dist/tools/portfolio/watchlist.js.map +1 -1
- package/dist/tools/sentiment/reddit-sentiment.js +24 -11
- package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
- package/dist/tools/sentiment/sentiment-summary.js +71 -14
- package/dist/tools/sentiment/sentiment-summary.js.map +1 -1
- package/dist/tools/sentiment/sentiment-trend.d.ts +1 -1
- package/dist/tools/sentiment/sentiment-trend.js +12 -2
- package/dist/tools/sentiment/sentiment-trend.js.map +1 -1
- package/dist/tools/sentiment/twitter-sentiment.js +13 -6
- package/dist/tools/sentiment/twitter-sentiment.js.map +1 -1
- package/dist/tools/sentiment/untrusted-text.d.ts +2 -0
- package/dist/tools/sentiment/untrusted-text.js +17 -0
- package/dist/tools/sentiment/untrusted-text.js.map +1 -0
- package/dist/tools/sentiment/web-search.js +37 -12
- package/dist/tools/sentiment/web-search.js.map +1 -1
- package/dist/tools/sentiment/web-sentiment.js +16 -4
- package/dist/tools/sentiment/web-sentiment.js.map +1 -1
- package/dist/tools/technical/backtest.d.ts +3 -3
- package/dist/tools/technical/backtest.js +65 -44
- package/dist/tools/technical/backtest.js.map +1 -1
- package/dist/tools/technical/indicators.js +24 -8
- package/dist/tools/technical/indicators.js.map +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/market.d.ts +1 -0
- package/dist/types/options.d.ts +10 -0
- package/dist/types/portfolio.d.ts +41 -4
- package/dist/workflows/compare-assets.d.ts +0 -3
- package/dist/workflows/compare-assets.js +55 -10
- package/dist/workflows/compare-assets.js.map +1 -1
- package/dist/workflows/index.d.ts +3 -4
- package/dist/workflows/index.js +3 -3
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/options-screener.d.ts +0 -3
- package/dist/workflows/options-screener.js +88 -14
- package/dist/workflows/options-screener.js.map +1 -1
- package/dist/workflows/portfolio-builder.d.ts +0 -3
- package/dist/workflows/portfolio-builder.js +7 -11
- package/dist/workflows/portfolio-builder.js.map +1 -1
- package/gui/server/ask-user-bridge.ts +82 -0
- package/gui/server/automation-heartbeat.ts +97 -0
- package/gui/server/background-quotes.ts +97 -1
- package/gui/server/chat-event-adapter.ts +32 -10
- package/gui/server/chat-run-session.ts +16 -0
- package/gui/server/gui-session-manager.ts +5 -0
- package/gui/server/invoke-tool.ts +144 -1
- package/gui/server/live-chat-event-adapter.ts +21 -6
- package/gui/server/market-state-api.ts +315 -0
- package/gui/server/model-setup.ts +149 -2
- package/gui/server/private-api-access.ts +62 -0
- package/gui/server/projector.ts +58 -11
- package/gui/server/prompt-observation.ts +58 -0
- package/gui/server/quote-snapshot-store.ts +50 -0
- package/gui/server/server.ts +236 -376
- package/gui/server/session-actions.ts +186 -1
- package/gui/server/session-entry-wait.ts +81 -0
- package/gui/server/shutdown.ts +47 -0
- package/gui/server/tool-invoke-ack.ts +49 -0
- package/gui/server/tool-metadata.ts +23 -10
- package/gui/server/websocket.ts +13 -3
- package/gui/server/writer-lock.ts +6 -2
- package/gui/server/ws-hub.ts +292 -0
- package/gui/shared/chat-events.ts +16 -1
- package/gui/shared/event-reducer.ts +24 -6
- package/gui/web/dist/assets/CatalogOverlay-eJ2cBk33.js +1 -0
- package/gui/web/dist/assets/index-2KZtKBmu.css +1 -0
- package/gui/web/dist/assets/index-CveNgtDg.js +69 -0
- package/gui/web/dist/index.html +2 -2
- package/package.json +22 -12
- package/src/analysts/contracts.ts +10 -23
- package/src/analysts/orchestrator.ts +8 -43
- package/src/cli.ts +37 -13
- package/src/config.ts +99 -7
- package/src/index.ts +1 -1
- package/src/infra/browser.ts +4 -2
- package/src/infra/cache.ts +41 -30
- package/src/infra/http-client.ts +72 -6
- package/src/infra/index.ts +7 -10
- package/src/infra/native-dependencies.ts +8 -3
- package/src/infra/node-version.ts +3 -1
- package/src/infra/opencandle-paths.ts +3 -14
- package/src/infra/rate-limiter.ts +32 -20
- package/src/market-state/alert-conditions.ts +82 -0
- package/src/market-state/alert-runner.ts +863 -0
- package/src/market-state/daily-report.ts +247 -0
- package/src/market-state/local-automation-service.ts +162 -0
- package/src/market-state/notification-delivery.ts +158 -0
- package/src/market-state/resolve-for-mutation.ts +24 -0
- package/src/market-state/resolve.ts +112 -0
- package/src/market-state/service.ts +2344 -0
- package/src/memory/index.ts +7 -7
- package/src/memory/manager.ts +57 -26
- package/src/memory/retrieval.ts +8 -7
- package/src/memory/sqlite.ts +407 -6
- package/src/memory/storage.ts +8 -17
- package/src/memory/tool-defaults.ts +60 -39
- package/src/memory/types.ts +7 -3
- package/src/monitor.ts +121 -0
- package/src/onboarding/connect.ts +10 -33
- package/src/onboarding/credential-interceptor.ts +3 -15
- package/src/onboarding/degradation-accumulator.ts +1 -3
- package/src/onboarding/providers.ts +9 -40
- package/src/onboarding/state.ts +4 -15
- package/src/onboarding/tool-helpers.ts +2 -9
- package/src/onboarding/tool-tags.ts +6 -6
- package/src/onboarding/validation.ts +14 -20
- package/src/pi/opencandle-extension.ts +795 -120
- package/src/pi/session.ts +7 -5
- package/src/pi/setup.ts +61 -33
- package/src/pi/tool-adapter.ts +5 -2
- package/src/prompts/context-builder.ts +143 -21
- package/src/prompts/disclaimer.ts +1 -1
- package/src/prompts/policy-cards.ts +220 -0
- package/src/prompts/sections.ts +4 -4
- package/src/prompts/symbol-preflight.ts +80 -0
- package/src/prompts/workflow-prompts.ts +231 -28
- package/src/providers/alpha-vantage.ts +82 -40
- package/src/providers/coingecko.ts +2 -5
- package/src/providers/errors.ts +9 -0
- package/src/providers/exa-search.ts +24 -22
- package/src/providers/fear-greed.ts +1 -1
- package/src/providers/finnhub.ts +7 -6
- package/src/providers/fred.ts +3 -3
- package/src/providers/index.ts +14 -6
- package/src/providers/reddit.ts +17 -6
- package/src/providers/sec-edgar.ts +235 -5
- package/src/providers/tradingview.ts +399 -0
- package/src/providers/twitter.ts +6 -8
- package/src/providers/web-search.ts +30 -20
- package/src/providers/with-fallback.ts +8 -7
- package/src/providers/wrap-provider.ts +15 -10
- package/src/providers/yahoo-finance.ts +292 -20
- package/src/routing/classify-intent.ts +186 -4
- package/src/routing/defaults.ts +4 -4
- package/src/routing/entity-extractor.ts +428 -28
- package/src/routing/fund-symbols.ts +58 -0
- package/src/routing/horizon.ts +7 -0
- package/src/routing/index.ts +60 -16
- package/src/routing/legacy-rule-router.ts +13 -0
- package/src/routing/planning.ts +823 -0
- package/src/routing/route-manifest.ts +309 -0
- package/src/routing/router-llm-client.ts +4 -4
- package/src/routing/router-prompt.ts +52 -52
- package/src/routing/router-types.ts +18 -0
- package/src/routing/router.ts +717 -20
- package/src/routing/slot-resolver.ts +75 -14
- package/src/routing/symbol-disambiguator.ts +72 -0
- package/src/routing/turn-context.ts +108 -0
- package/src/routing/types.ts +15 -1
- package/src/runtime/answer-contracts.ts +672 -0
- package/src/runtime/artifact-contracts.ts +77 -0
- package/src/runtime/planning-evidence.ts +682 -0
- package/src/runtime/prompt-step.ts +1 -16
- package/src/runtime/run-context.ts +12 -2
- package/src/runtime/session-coordinator.ts +297 -56
- package/src/runtime/session-title.ts +60 -0
- package/src/runtime/tool-defaults-wrapper.ts +1 -3
- package/src/runtime/validation.ts +1 -4
- package/src/runtime/workflow-events.ts +7 -7
- package/src/runtime/workflow-runner.ts +5 -11
- package/src/sentiment/adapters/finnhub.ts +7 -2
- package/src/sentiment/adapters/reddit.ts +2 -2
- package/src/sentiment/adapters/twitter.ts +1 -1
- package/src/sentiment/adapters/web.ts +1 -1
- package/src/sentiment/index.ts +16 -26
- package/src/sentiment/keywords.ts +26 -4
- package/src/sentiment/pipeline.ts +15 -4
- package/src/sentiment/scorer.ts +1 -1
- package/src/sentiment/store.ts +2 -2
- package/src/sentiment/trends.ts +9 -3
- package/src/sentiment/types.ts +5 -4
- package/src/system-prompt.ts +7 -3
- package/src/tool-kit.ts +10 -9
- package/src/tools/fundamentals/company-overview.ts +20 -10
- package/src/tools/fundamentals/comps.ts +69 -56
- package/src/tools/fundamentals/dcf.ts +146 -96
- package/src/tools/fundamentals/earnings.ts +17 -7
- package/src/tools/fundamentals/financials.ts +17 -8
- package/src/tools/fundamentals/sec-filings.ts +52 -8
- package/src/tools/index.ts +53 -38
- package/src/tools/interaction/ask-user.ts +22 -10
- package/src/tools/interaction/twitter-login.ts +17 -5
- package/src/tools/macro/fear-greed.ts +2 -2
- package/src/tools/macro/fred-data.ts +80 -42
- package/src/tools/market/crypto-history.ts +25 -4
- package/src/tools/market/crypto-price.ts +7 -7
- package/src/tools/market/screen-stocks.ts +279 -0
- package/src/tools/market/search-ticker.ts +219 -18
- package/src/tools/market/stock-history.ts +38 -13
- package/src/tools/market/stock-quote.ts +11 -8
- package/src/tools/options/greeks.ts +5 -6
- package/src/tools/options/option-chain.ts +47 -18
- package/src/tools/portfolio/alerts.ts +457 -0
- package/src/tools/portfolio/correlation.ts +48 -21
- package/src/tools/portfolio/daily-report.ts +101 -0
- package/src/tools/portfolio/holdings-overlap.ts +139 -0
- package/src/tools/portfolio/notifications.ts +45 -0
- package/src/tools/portfolio/predictions.ts +407 -107
- package/src/tools/portfolio/risk-analysis.ts +47 -8
- package/src/tools/portfolio/tracker.ts +271 -110
- package/src/tools/portfolio/watchlist.ts +251 -116
- package/src/tools/sentiment/reddit-sentiment.ts +51 -25
- package/src/tools/sentiment/sentiment-summary.ts +116 -35
- package/src/tools/sentiment/sentiment-trend.ts +24 -7
- package/src/tools/sentiment/twitter-sentiment.ts +23 -16
- package/src/tools/sentiment/untrusted-text.ts +21 -0
- package/src/tools/sentiment/web-search.ts +52 -16
- package/src/tools/sentiment/web-sentiment.ts +27 -11
- package/src/tools/technical/backtest.ts +78 -47
- package/src/tools/technical/indicators.ts +40 -17
- package/src/types/index.ts +8 -3
- package/src/types/market.ts +1 -0
- package/src/types/options.ts +17 -0
- package/src/types/portfolio.ts +46 -4
- package/src/types/sentiment.ts +2 -2
- package/src/workflows/compare-assets.ts +67 -19
- package/src/workflows/index.ts +3 -4
- package/src/workflows/options-screener.ts +98 -22
- package/src/workflows/portfolio-builder.ts +40 -29
- package/dist/runtime/index.d.ts +0 -16
- package/dist/runtime/index.js +0 -10
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/provider-ids.d.ts +0 -14
- package/dist/runtime/provider-ids.js +0 -14
- package/dist/runtime/provider-ids.js.map +0 -1
- package/dist/workflows/types.d.ts +0 -4
- package/dist/workflows/types.js +0 -2
- package/dist/workflows/types.js.map +0 -1
- package/gui/web/dist/assets/CatalogOverlay-D1ImSJTe.js +0 -1
- package/gui/web/dist/assets/index-DBrWq43L.css +0 -1
- package/gui/web/dist/assets/index-RflHaj0y.js +0 -67
- package/src/runtime/index.ts +0 -55
- package/src/runtime/provider-ids.ts +0 -15
- package/src/workflows/types.ts +0 -4
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
1
|
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
3
|
-
import {
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
4
3
|
import { wrapProvider } from "../../providers/wrap-provider.js";
|
|
5
|
-
import {
|
|
4
|
+
import { getHistory } from "../../providers/yahoo-finance.js";
|
|
6
5
|
import type { OHLCV } from "../../types/market.js";
|
|
6
|
+
import { computeRSI, computeSMA } from "./indicators.js";
|
|
7
7
|
|
|
8
|
-
export type Strategy = "sma_crossover" | "rsi_mean_reversion";
|
|
8
|
+
export type Strategy = "sma_crossover" | "sma_50_200_crossover" | "rsi_mean_reversion";
|
|
9
9
|
|
|
10
10
|
export interface BacktestResult {
|
|
11
11
|
strategy: string;
|
|
@@ -20,28 +20,32 @@ export interface BacktestResult {
|
|
|
20
20
|
|
|
21
21
|
export function runBacktest(bars: OHLCV[], strategy: Strategy): BacktestResult {
|
|
22
22
|
const closes = bars.map((b) => b.close);
|
|
23
|
-
const buyAndHoldReturn = closes.length > 1
|
|
24
|
-
? (closes[closes.length - 1] - closes[0]) / closes[0]
|
|
25
|
-
: 0;
|
|
26
23
|
|
|
27
24
|
if (strategy === "sma_crossover") {
|
|
28
|
-
return backtestSMACrossover(bars, closes);
|
|
25
|
+
return backtestSMACrossover(bars, closes, 20, 50, strategy);
|
|
26
|
+
}
|
|
27
|
+
if (strategy === "sma_50_200_crossover") {
|
|
28
|
+
return backtestSMACrossover(bars, closes, 50, 200, strategy);
|
|
29
29
|
}
|
|
30
30
|
return backtestRSIMeanReversion(bars, closes);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function backtestSMACrossover(
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
function backtestSMACrossover(
|
|
34
|
+
bars: OHLCV[],
|
|
35
|
+
closes: number[],
|
|
36
|
+
shortWindow: number,
|
|
37
|
+
longWindow: number,
|
|
38
|
+
strategyName: Strategy,
|
|
39
|
+
): BacktestResult {
|
|
40
|
+
const shortSma = computeSMA(closes, shortWindow);
|
|
41
|
+
const longSma = computeSMA(closes, longWindow);
|
|
36
42
|
|
|
37
|
-
if (
|
|
38
|
-
return emptyResult(
|
|
43
|
+
if (longSma.length === 0) {
|
|
44
|
+
return emptyResult(strategyName, closes);
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const offset20 = 19;
|
|
44
|
-
const offset50 = 49;
|
|
47
|
+
const shortOffset = shortWindow - 1;
|
|
48
|
+
const longOffset = longWindow - 1;
|
|
45
49
|
|
|
46
50
|
let position = false;
|
|
47
51
|
let entryPrice = 0;
|
|
@@ -50,19 +54,19 @@ function backtestSMACrossover(bars: OHLCV[], closes: number[]): BacktestResult {
|
|
|
50
54
|
let peak = 1.0;
|
|
51
55
|
let maxDd = 0;
|
|
52
56
|
|
|
53
|
-
for (let i = 0; i <
|
|
54
|
-
const barIdx = i +
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
57
|
+
for (let i = 0; i < longSma.length; i++) {
|
|
58
|
+
const barIdx = i + longOffset;
|
|
59
|
+
const shortSmaIdx = i + (longOffset - shortOffset);
|
|
60
|
+
const sShort = shortSma[shortSmaIdx];
|
|
61
|
+
const sLong = longSma[i];
|
|
58
62
|
const price = closes[barIdx];
|
|
59
63
|
|
|
60
|
-
if (!position &&
|
|
64
|
+
if (!position && sShort > sLong && price > 0) {
|
|
61
65
|
// Buy signal
|
|
62
66
|
position = true;
|
|
63
67
|
entryPrice = price;
|
|
64
68
|
tradeLog.push({ type: "buy", date: bars[barIdx].date, price });
|
|
65
|
-
} else if (position &&
|
|
69
|
+
} else if (position && sShort < sLong) {
|
|
66
70
|
// Sell signal
|
|
67
71
|
const pnl = (price - entryPrice) / entryPrice;
|
|
68
72
|
equity *= 1 + pnl;
|
|
@@ -71,9 +75,7 @@ function backtestSMACrossover(bars: OHLCV[], closes: number[]): BacktestResult {
|
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
// Track mark-to-market equity for accurate drawdown
|
|
74
|
-
const currentEquity = position
|
|
75
|
-
? equity * (1 + (price - entryPrice) / entryPrice)
|
|
76
|
-
: equity;
|
|
78
|
+
const currentEquity = position ? equity * (1 + (price - entryPrice) / entryPrice) : equity;
|
|
77
79
|
if (currentEquity > peak) peak = currentEquity;
|
|
78
80
|
const dd = (peak - currentEquity) / peak;
|
|
79
81
|
if (dd > maxDd) maxDd = dd;
|
|
@@ -87,7 +89,7 @@ function backtestSMACrossover(bars: OHLCV[], closes: number[]): BacktestResult {
|
|
|
87
89
|
tradeLog.push({ type: "sell", date: bars[bars.length - 1].date, price: lastPrice, pnl });
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
return buildResult(
|
|
92
|
+
return buildResult(strategyName, equity - 1, closes, tradeLog, maxDd);
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
function backtestRSIMeanReversion(bars: OHLCV[], closes: number[]): BacktestResult {
|
|
@@ -111,7 +113,7 @@ function backtestRSIMeanReversion(bars: OHLCV[], closes: number[]): BacktestResu
|
|
|
111
113
|
const r = rsi[i];
|
|
112
114
|
const price = closes[barIdx];
|
|
113
115
|
|
|
114
|
-
if (!position && r < 30) {
|
|
116
|
+
if (!position && r < 30 && price > 0) {
|
|
115
117
|
// RSI oversold → buy
|
|
116
118
|
position = true;
|
|
117
119
|
entryPrice = price;
|
|
@@ -125,9 +127,7 @@ function backtestRSIMeanReversion(bars: OHLCV[], closes: number[]): BacktestResu
|
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
// Track mark-to-market equity for accurate drawdown
|
|
128
|
-
const currentEquity = position
|
|
129
|
-
? equity * (1 + (price - entryPrice) / entryPrice)
|
|
130
|
-
: equity;
|
|
130
|
+
const currentEquity = position ? equity * (1 + (price - entryPrice) / entryPrice) : equity;
|
|
131
131
|
if (currentEquity > peak) peak = currentEquity;
|
|
132
132
|
const dd = (peak - currentEquity) / peak;
|
|
133
133
|
if (dd > maxDd) maxDd = dd;
|
|
@@ -153,9 +153,8 @@ function buildResult(
|
|
|
153
153
|
): BacktestResult {
|
|
154
154
|
const sellTrades = tradeLog.filter((t) => t.type === "sell" && t.pnl != null);
|
|
155
155
|
const wins = sellTrades.filter((t) => t.pnl! > 0).length;
|
|
156
|
-
const buyAndHoldReturn =
|
|
157
|
-
? (closes[closes.length - 1] - closes[0]) / closes[0]
|
|
158
|
-
: 0;
|
|
156
|
+
const buyAndHoldReturn =
|
|
157
|
+
closes.length > 1 && closes[0] > 0 ? (closes[closes.length - 1] - closes[0]) / closes[0] : 0;
|
|
159
158
|
|
|
160
159
|
return {
|
|
161
160
|
strategy,
|
|
@@ -173,9 +172,8 @@ function emptyResult(strategy: string, closes: number[]): BacktestResult {
|
|
|
173
172
|
return {
|
|
174
173
|
strategy,
|
|
175
174
|
totalReturn: 0,
|
|
176
|
-
buyAndHoldReturn:
|
|
177
|
-
? (closes[closes.length - 1] - closes[0]) / closes[0]
|
|
178
|
-
: 0,
|
|
175
|
+
buyAndHoldReturn:
|
|
176
|
+
closes.length > 1 && closes[0] > 0 ? (closes[closes.length - 1] - closes[0]) / closes[0] : 0,
|
|
179
177
|
trades: 0,
|
|
180
178
|
wins: 0,
|
|
181
179
|
winRate: 0,
|
|
@@ -187,11 +185,20 @@ function emptyResult(strategy: string, closes: number[]): BacktestResult {
|
|
|
187
185
|
const params = Type.Object({
|
|
188
186
|
symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT, SPY)" }),
|
|
189
187
|
strategy: Type.Union(
|
|
190
|
-
[
|
|
191
|
-
|
|
188
|
+
[
|
|
189
|
+
Type.Literal("sma_crossover"),
|
|
190
|
+
Type.Literal("sma_50_200_crossover"),
|
|
191
|
+
Type.Literal("rsi_mean_reversion"),
|
|
192
|
+
],
|
|
193
|
+
{
|
|
194
|
+
description:
|
|
195
|
+
"Strategy: sma_crossover (buy when SMA20 > SMA50, sell on reverse), sma_50_200_crossover (buy when SMA50 > SMA200, sell on reverse), or rsi_mean_reversion (buy when RSI < 30, sell when RSI > 70)",
|
|
196
|
+
},
|
|
192
197
|
),
|
|
193
198
|
period: Type.Optional(
|
|
194
|
-
Type.
|
|
199
|
+
Type.Union([Type.Literal("1y"), Type.Literal("2y"), Type.Literal("5y")], {
|
|
200
|
+
description: "Historical period to backtest: 1y, 2y, 5y. Default: 2y",
|
|
201
|
+
}),
|
|
195
202
|
),
|
|
196
203
|
});
|
|
197
204
|
|
|
@@ -199,23 +206,31 @@ export const backtestTool: AgentTool<typeof params> = {
|
|
|
199
206
|
name: "backtest_strategy",
|
|
200
207
|
label: "Backtest Strategy",
|
|
201
208
|
description:
|
|
202
|
-
"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.",
|
|
209
|
+
"Backtest a simple trading strategy against historical data. Supported strategies: SMA crossover (SMA20/SMA50), standard long-term SMA crossover (SMA50/SMA200), and RSI mean-reversion (buy <30, sell >70). Returns total return, win rate, max drawdown, and comparison to buy-and-hold.",
|
|
203
210
|
parameters: params,
|
|
204
|
-
async execute(
|
|
211
|
+
async execute(_toolCallId, args) {
|
|
205
212
|
const symbol = args.symbol.toUpperCase();
|
|
206
213
|
const period = args.period ?? "2y";
|
|
207
214
|
const historyResult = await wrapProvider("yahoo", () => getHistory(symbol, period, "1d"));
|
|
208
215
|
if (historyResult.status === "unavailable") {
|
|
209
216
|
return {
|
|
210
|
-
content: [
|
|
217
|
+
content: [
|
|
218
|
+
{ type: "text", text: `⚠ Backtest unavailable for ${symbol} (${historyResult.reason}).` },
|
|
219
|
+
],
|
|
211
220
|
details: null as any,
|
|
212
221
|
};
|
|
213
222
|
}
|
|
214
223
|
const bars = historyResult.data;
|
|
215
224
|
|
|
216
|
-
|
|
225
|
+
const minBars = requiredBarsForStrategy(args.strategy);
|
|
226
|
+
if (bars.length < minBars) {
|
|
217
227
|
return {
|
|
218
|
-
content: [
|
|
228
|
+
content: [
|
|
229
|
+
{
|
|
230
|
+
type: "text",
|
|
231
|
+
text: `Insufficient data for backtesting ${symbol} (need ${minBars}+ days, got ${bars.length})`,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
219
234
|
details: null,
|
|
220
235
|
};
|
|
221
236
|
}
|
|
@@ -224,7 +239,7 @@ export const backtestTool: AgentTool<typeof params> = {
|
|
|
224
239
|
|
|
225
240
|
const outperformance = result.totalReturn - result.buyAndHoldReturn;
|
|
226
241
|
const lines = [
|
|
227
|
-
`**${symbol} Backtest: ${args.strategy}** (${bars[0].date} to ${bars[bars.length - 1].date}, ${bars.length} days)`,
|
|
242
|
+
`**${symbol} Backtest: ${strategyLabel(args.strategy)}** (${bars[0].date} to ${bars[bars.length - 1].date}, ${bars.length} days)`,
|
|
228
243
|
``,
|
|
229
244
|
`Strategy Return: ${(result.totalReturn * 100).toFixed(2)}%`,
|
|
230
245
|
`Buy & Hold Return: ${(result.buyAndHoldReturn * 100).toFixed(2)}%`,
|
|
@@ -244,3 +259,19 @@ export const backtestTool: AgentTool<typeof params> = {
|
|
|
244
259
|
};
|
|
245
260
|
},
|
|
246
261
|
};
|
|
262
|
+
|
|
263
|
+
function requiredBarsForStrategy(strategy: Strategy): number {
|
|
264
|
+
if (strategy === "sma_50_200_crossover") return 200;
|
|
265
|
+
return 60;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function strategyLabel(strategy: Strategy): string {
|
|
269
|
+
switch (strategy) {
|
|
270
|
+
case "sma_crossover":
|
|
271
|
+
return "SMA 20/50 Crossover";
|
|
272
|
+
case "sma_50_200_crossover":
|
|
273
|
+
return "SMA 50/200 Crossover";
|
|
274
|
+
case "rsi_mean_reversion":
|
|
275
|
+
return "RSI Mean Reversion";
|
|
276
|
+
}
|
|
277
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
1
|
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
3
|
-
import {
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
4
3
|
import { wrapProvider } from "../../providers/wrap-provider.js";
|
|
4
|
+
import { getHistory } from "../../providers/yahoo-finance.js";
|
|
5
5
|
import type { OHLCV } from "../../types/market.js";
|
|
6
6
|
|
|
7
7
|
// --- Volume-based indicators ---
|
|
@@ -46,13 +46,18 @@ export const technicalIndicatorsTool: AgentTool<typeof params> = {
|
|
|
46
46
|
description:
|
|
47
47
|
"Compute technical indicators (SMA, EMA, RSI, MACD, Bollinger Bands) from historical price data. All computed locally — no API dependency.",
|
|
48
48
|
parameters: params,
|
|
49
|
-
async execute(
|
|
49
|
+
async execute(_toolCallId, args) {
|
|
50
50
|
const symbol = args.symbol.toUpperCase();
|
|
51
51
|
const range = args.range ?? "1y";
|
|
52
52
|
const result = await wrapProvider("yahoo", () => getHistory(symbol, range, "1d"));
|
|
53
53
|
if (result.status === "unavailable") {
|
|
54
54
|
return {
|
|
55
|
-
content: [
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: "text",
|
|
58
|
+
text: `⚠ Technical indicators unavailable for ${symbol} (${result.reason}).`,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
56
61
|
details: null as any,
|
|
57
62
|
};
|
|
58
63
|
}
|
|
@@ -61,15 +66,18 @@ export const technicalIndicatorsTool: AgentTool<typeof params> = {
|
|
|
61
66
|
|
|
62
67
|
if (closes.length < 26) {
|
|
63
68
|
return {
|
|
64
|
-
content: [
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: "text",
|
|
72
|
+
text: `Insufficient data for ${symbol} (need 26+ bars, got ${closes.length})`,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
65
75
|
details: null,
|
|
66
76
|
};
|
|
67
77
|
}
|
|
68
78
|
|
|
69
79
|
const sma20 = computeSMA(closes, 20);
|
|
70
80
|
const sma50 = computeSMA(closes, 50);
|
|
71
|
-
const ema12 = computeEMA(closes, 12);
|
|
72
|
-
const ema26 = computeEMA(closes, 26);
|
|
73
81
|
const rsi = computeRSI(closes, 14);
|
|
74
82
|
const macd = computeMACD(closes);
|
|
75
83
|
const bb = computeBollingerBands(closes, 20, 2);
|
|
@@ -81,9 +89,12 @@ export const technicalIndicatorsTool: AgentTool<typeof params> = {
|
|
|
81
89
|
const latestMacd = macd[macd.length - 1];
|
|
82
90
|
const latestBB = bb[bb.length - 1];
|
|
83
91
|
const latestVwap = vwap[vwap.length - 1];
|
|
84
|
-
const obvTrend =
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
const obvTrend =
|
|
93
|
+
obv.length >= 20
|
|
94
|
+
? obv[obv.length - 1] > obv[obv.length - 20]
|
|
95
|
+
? "Rising"
|
|
96
|
+
: "Falling"
|
|
97
|
+
: "N/A";
|
|
87
98
|
|
|
88
99
|
const lines = [
|
|
89
100
|
`**${symbol} Technical Analysis** (${bars[0].date} to ${bars[bars.length - 1].date})`,
|
|
@@ -105,7 +116,13 @@ export const technicalIndicatorsTool: AgentTool<typeof params> = {
|
|
|
105
116
|
range,
|
|
106
117
|
prices: closes,
|
|
107
118
|
dates: bars.map((b) => b.date),
|
|
108
|
-
sma20,
|
|
119
|
+
sma20,
|
|
120
|
+
sma50,
|
|
121
|
+
rsi,
|
|
122
|
+
macd,
|
|
123
|
+
bb,
|
|
124
|
+
obv,
|
|
125
|
+
vwap,
|
|
109
126
|
},
|
|
110
127
|
};
|
|
111
128
|
},
|
|
@@ -243,16 +260,22 @@ function trendSummary(
|
|
|
243
260
|
|
|
244
261
|
if (latestSma20 && price > latestSma20) signals.push("Price above SMA(20) — short-term bullish");
|
|
245
262
|
if (latestSma20 && price < latestSma20) signals.push("Price below SMA(20) — short-term bearish");
|
|
246
|
-
if (latestSma20 && latestSma50 && latestSma20 > latestSma50)
|
|
247
|
-
|
|
263
|
+
if (latestSma20 && latestSma50 && latestSma20 > latestSma50)
|
|
264
|
+
signals.push("Golden cross pattern (SMA20 > SMA50)");
|
|
265
|
+
if (latestSma20 && latestSma50 && latestSma20 < latestSma50)
|
|
266
|
+
signals.push("Death cross pattern (SMA20 < SMA50)");
|
|
248
267
|
if (rsi != null && rsi >= 70) signals.push("RSI overbought — potential reversal");
|
|
249
268
|
if (rsi != null && rsi <= 30) signals.push("RSI oversold — potential bounce");
|
|
250
269
|
if (macd && macd.histogram > 0) signals.push("MACD bullish (histogram positive)");
|
|
251
270
|
if (macd && macd.histogram < 0) signals.push("MACD bearish (histogram negative)");
|
|
252
|
-
if (obvTrend === "Rising" && price > (latestSma20 ?? 0))
|
|
253
|
-
|
|
254
|
-
if (
|
|
255
|
-
|
|
271
|
+
if (obvTrend === "Rising" && price > (latestSma20 ?? 0))
|
|
272
|
+
signals.push("Volume confirming price advance (OBV rising)");
|
|
273
|
+
if (obvTrend === "Falling" && price < (latestSma20 ?? Infinity))
|
|
274
|
+
signals.push("Volume confirming price decline (OBV falling)");
|
|
275
|
+
if (vwap != null && price > vwap)
|
|
276
|
+
signals.push("Price above cumulative VWAP — bullish volume-weighted bias");
|
|
277
|
+
if (vwap != null && price < vwap)
|
|
278
|
+
signals.push("Price below cumulative VWAP — bearish volume-weighted bias");
|
|
256
279
|
|
|
257
280
|
return signals.length > 0 ? "Signals: " + signals.join(" | ") : "No strong signals";
|
|
258
281
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
export type { StockQuote, OHLCV, CryptoPrice } from "./market.js";
|
|
2
1
|
export type { CompanyOverview, EarningsData, FinancialStatement } from "./fundamentals.js";
|
|
3
2
|
export type { FredObservation, FredSeries } from "./macro.js";
|
|
4
3
|
export { FRED_SERIES } from "./macro.js";
|
|
4
|
+
export type { CryptoPrice, OHLCV, StockQuote } from "./market.js";
|
|
5
5
|
export type { Greeks, OptionContract, OptionsChain } from "./options.js";
|
|
6
|
-
export type {
|
|
7
|
-
export type {
|
|
6
|
+
export type { PortfolioSummary, Position, RiskMetrics, TechnicalIndicators } from "./portfolio.js";
|
|
7
|
+
export type {
|
|
8
|
+
FearGreedData,
|
|
9
|
+
RedditSentimentResult,
|
|
10
|
+
WebSearchEnvelope,
|
|
11
|
+
WebSearchResult,
|
|
12
|
+
} from "./sentiment.js";
|
|
8
13
|
|
|
9
14
|
/**
|
|
10
15
|
* Handler for `ask_user` tool invocations in non-UI contexts (e.g. test harness).
|
package/src/types/market.ts
CHANGED
package/src/types/options.ts
CHANGED
|
@@ -21,6 +21,22 @@ export interface OptionContract {
|
|
|
21
21
|
greeks: Greeks;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export type OptionsMarketSession = "pre_market" | "regular" | "after_hours" | "closed";
|
|
25
|
+
|
|
26
|
+
export type OptionsBidAskState =
|
|
27
|
+
| "live_quotes"
|
|
28
|
+
| "closed_market_or_stale_quotes"
|
|
29
|
+
| "live_zero_bid_ask"
|
|
30
|
+
| "mixed_or_unknown";
|
|
31
|
+
|
|
32
|
+
export interface OptionsQuoteStatus {
|
|
33
|
+
marketSession: OptionsMarketSession;
|
|
34
|
+
bidAskState: OptionsBidAskState;
|
|
35
|
+
zeroBidAskContracts: number;
|
|
36
|
+
totalContracts: number;
|
|
37
|
+
warning?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
24
40
|
export interface OptionsChain {
|
|
25
41
|
symbol: string;
|
|
26
42
|
underlyingPrice: number;
|
|
@@ -31,5 +47,6 @@ export interface OptionsChain {
|
|
|
31
47
|
totalCallVolume: number;
|
|
32
48
|
totalPutVolume: number;
|
|
33
49
|
putCallRatio: number;
|
|
50
|
+
quoteStatus: OptionsQuoteStatus;
|
|
34
51
|
fetchedAt: string;
|
|
35
52
|
}
|
package/src/types/portfolio.ts
CHANGED
|
@@ -2,23 +2,33 @@ export interface Position {
|
|
|
2
2
|
symbol: string;
|
|
3
3
|
shares: number;
|
|
4
4
|
avgCost: number;
|
|
5
|
+
currency: string;
|
|
5
6
|
addedAt: string;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export interface PortfolioSummary {
|
|
9
10
|
positions: Array<
|
|
10
11
|
Position & {
|
|
11
|
-
currentPrice: number;
|
|
12
|
-
marketValue: number;
|
|
12
|
+
currentPrice: number | null;
|
|
13
|
+
marketValue: number | null;
|
|
13
14
|
totalCost: number;
|
|
14
|
-
pnl: number;
|
|
15
|
-
pnlPercent: number;
|
|
15
|
+
pnl: number | null;
|
|
16
|
+
pnlPercent: number | null;
|
|
17
|
+
includedInTotals: boolean;
|
|
18
|
+
quoteStatus?: "ok" | "unavailable";
|
|
19
|
+
exclusionReason?: string;
|
|
16
20
|
}
|
|
17
21
|
>;
|
|
22
|
+
baseCurrency: string;
|
|
18
23
|
totalValue: number;
|
|
19
24
|
totalCost: number;
|
|
20
25
|
totalPnl: number;
|
|
21
26
|
totalPnlPercent: number;
|
|
27
|
+
excludedFromTotals: Array<{
|
|
28
|
+
symbol: string;
|
|
29
|
+
currency: string;
|
|
30
|
+
reason: string;
|
|
31
|
+
}>;
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
export interface RiskMetrics {
|
|
@@ -30,6 +40,38 @@ export interface RiskMetrics {
|
|
|
30
40
|
var95: number; // 95% Value at Risk (daily)
|
|
31
41
|
}
|
|
32
42
|
|
|
43
|
+
export interface FundHolding {
|
|
44
|
+
symbol: string;
|
|
45
|
+
name: string;
|
|
46
|
+
weight: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface FundHoldings {
|
|
50
|
+
symbol: string;
|
|
51
|
+
name?: string;
|
|
52
|
+
provider: string;
|
|
53
|
+
holdings: FundHolding[];
|
|
54
|
+
sectorWeights?: Record<string, number>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface SharedFundHolding {
|
|
58
|
+
symbol: string;
|
|
59
|
+
name: string;
|
|
60
|
+
weights: Record<string, number>;
|
|
61
|
+
overlapWeight: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface FundOverlapPair {
|
|
65
|
+
symbols: [string, string];
|
|
66
|
+
overlapWeight: number;
|
|
67
|
+
sharedHoldings: SharedFundHolding[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface FundHoldingsOverlap {
|
|
71
|
+
funds: FundHoldings[];
|
|
72
|
+
pairs: FundOverlapPair[];
|
|
73
|
+
}
|
|
74
|
+
|
|
33
75
|
export interface TechnicalIndicators {
|
|
34
76
|
symbol: string;
|
|
35
77
|
period: string;
|
package/src/types/sentiment.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface TwitterSentimentResult {
|
|
|
23
23
|
query: string;
|
|
24
24
|
tweetCount: number;
|
|
25
25
|
tweets: TwitterTweet[];
|
|
26
|
-
sentimentScore: number;
|
|
26
|
+
sentimentScore: number; // -1.0 (fully bearish) to +1.0 (fully bullish)
|
|
27
27
|
bullishCount: number;
|
|
28
28
|
bearishCount: number;
|
|
29
29
|
topMentions: string[];
|
|
@@ -63,7 +63,7 @@ export interface RedditSentimentResult {
|
|
|
63
63
|
created: string;
|
|
64
64
|
}>;
|
|
65
65
|
topMentions: string[];
|
|
66
|
-
sentimentScore: number;
|
|
66
|
+
sentimentScore: number; // -1.0 (fully bearish) to +1.0 (fully bullish)
|
|
67
67
|
bullishCount: number;
|
|
68
68
|
bearishCount: number;
|
|
69
69
|
fetchedAt: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { CompareAssetsSlots, SlotResolution } from "../routing/types.js";
|
|
2
1
|
import { buildCompareAssetsPrompt } from "../prompts/workflow-prompts.js";
|
|
3
|
-
import
|
|
2
|
+
import { areLikelyFundOrIndexSymbols, isFundOrIndexAssetScope } from "../routing/fund-symbols.js";
|
|
3
|
+
import { isLongInvestmentHorizon } from "../routing/horizon.js";
|
|
4
|
+
import type { CompareAssetsSlots, SlotResolution } from "../routing/types.js";
|
|
4
5
|
import type { WorkflowDefinition } from "../runtime/prompt-step.js";
|
|
5
6
|
import { promptStep } from "../runtime/prompt-step.js";
|
|
6
7
|
|
|
@@ -8,6 +9,59 @@ export function buildCompareAssetsWorkflowDefinition(
|
|
|
8
9
|
resolution: SlotResolution<CompareAssetsSlots>,
|
|
9
10
|
): WorkflowDefinition {
|
|
10
11
|
const symbols = resolution.resolved.symbols.join(", ");
|
|
12
|
+
const timeHorizon = resolution.resolved.timeHorizon;
|
|
13
|
+
const isMacroHedge = resolution.resolved.metrics?.includes("macro_hedge") ?? false;
|
|
14
|
+
const isInterestRateSensitive = resolution.resolved.metrics?.includes("interest_rates") ?? false;
|
|
15
|
+
const isOverlapComparison = resolution.resolved.metrics?.includes("overlap") ?? false;
|
|
16
|
+
const hasFundContext =
|
|
17
|
+
isFundOrIndexAssetScope(resolution.resolved.assetScope) ||
|
|
18
|
+
areLikelyFundOrIndexSymbols(resolution.resolved.symbols);
|
|
19
|
+
const shouldProbeFundOverlap =
|
|
20
|
+
!isOverlapComparison && isLongInvestmentHorizon(timeHorizon) && hasFundContext;
|
|
21
|
+
const evidenceList = resolution.resolved.metrics?.includes("sentiment")
|
|
22
|
+
? "price, technical, risk, and sentiment data"
|
|
23
|
+
: isOverlapComparison
|
|
24
|
+
? "quote, holdings-overlap, and correlation data"
|
|
25
|
+
: shouldProbeFundOverlap
|
|
26
|
+
? "price, technical, risk, correlation, and holdings-overlap data when applicable"
|
|
27
|
+
: "price, technical, and risk data";
|
|
28
|
+
const horizonGuidance = timeHorizon
|
|
29
|
+
? `
|
|
30
|
+
- Start by directly answering whether these assets are reasonable to compare for a ${timeHorizon} horizon.
|
|
31
|
+
- Rank the evidence for that horizon: near-term catalysts, earnings/guidance, estimate revisions, forward-looking valuation evidence, sentiment, macro sensitivity, and company-specific risks before long-term historical metrics.
|
|
32
|
+
- Treat unavailable forward-looking evidence as a caveat instead of replacing it with unrelated historical certainty.`
|
|
33
|
+
: "";
|
|
34
|
+
const macroHedgeGuidance = isMacroHedge
|
|
35
|
+
? `
|
|
36
|
+
- Treat this as a macro hedge decision: explain each asset's hedge role, correlation regime, volatility/drawdown profile, and sensitivity to real yields, USD/liquidity, geopolitical shocks, and risk-off drawdowns.
|
|
37
|
+
- Do not let missing asset-specific metrics turn into a shallow default winner. Explain what each missing metric would have shown and how that lowers confidence.
|
|
38
|
+
- Give actionable conditional guidance: conditions under which each asset is the better capital-preservation hedge, diversifier, inflation hedge, duration hedge, liquidity sleeve, or higher-volatility asymmetric-upside sleeve.`
|
|
39
|
+
: "";
|
|
40
|
+
const interestRateGuidance = isInterestRateSensitive
|
|
41
|
+
? `
|
|
42
|
+
- For the rate-sensitive premise, separate benign falling rates from recessionary cuts and sticky-inflation/rate-reversal scenarios before giving the final tilt.
|
|
43
|
+
- Discuss concentration or sector-exposure risk when one asset is narrower or more growth-heavy than the other.
|
|
44
|
+
- Say whether the rate evidence you used is historical/current data or forward-looking market-pricing evidence; do not treat historical Fed funds data as a forecast.`
|
|
45
|
+
: "";
|
|
46
|
+
const overlapGuidance = isOverlapComparison
|
|
47
|
+
? `
|
|
48
|
+
- For ETF overlap prompts, synthesize the holdings-overlap and shared-exposure evidence first, with correlation only as supporting diversification context.
|
|
49
|
+
- State the diversification implication directly: deliberate factor tilt, accidental duplication, or genuinely differentiated exposure.
|
|
50
|
+
- If provider holdings coverage was partial or unavailable, say that before giving the practical next step.`
|
|
51
|
+
: shouldProbeFundOverlap
|
|
52
|
+
? `
|
|
53
|
+
- If these assets are ETFs, funds, or index products, synthesize holdings-overlap and shared-exposure evidence before correlation when that provider evidence is available.
|
|
54
|
+
- Compare fund role, broad style or sector tilt, dividend/income versus growth tradeoffs, taxable-account dividend drag, and any fetched expense ratio, yield, or AUM evidence.
|
|
55
|
+
- If expense ratio, yield, AUM, or constituent detail is unavailable, name that verification gap instead of filling it with approximate fund facts.
|
|
56
|
+
- If provider holdings coverage was partial or unavailable, say that before giving the practical next step.`
|
|
57
|
+
: "";
|
|
58
|
+
const verdictInstruction = isOverlapComparison
|
|
59
|
+
? "End with a concise verdict on whether the added fund improves diversification or mostly duplicates existing exposure."
|
|
60
|
+
: shouldProbeFundOverlap
|
|
61
|
+
? "End with a concise verdict tied to the user's horizon, fund roles, and diversification needs rather than short-term timing."
|
|
62
|
+
: timeHorizon
|
|
63
|
+
? `End with a concise verdict on which asset best fits the ${timeHorizon} horizon and why.`
|
|
64
|
+
: "End with a concise verdict on which asset looks strongest right now and why.";
|
|
11
65
|
|
|
12
66
|
return {
|
|
13
67
|
workflowType: "compare_assets",
|
|
@@ -16,24 +70,18 @@ export function buildCompareAssetsWorkflowDefinition(
|
|
|
16
70
|
requiredInputs: ["symbols"],
|
|
17
71
|
expectedOutputs: ["asset_data"],
|
|
18
72
|
}),
|
|
19
|
-
promptStep(
|
|
73
|
+
promptStep(
|
|
74
|
+
"compare_and_present",
|
|
75
|
+
"Present side-by-side comparison",
|
|
76
|
+
`Now present the side-by-side comparison for ${symbols}:
|
|
20
77
|
- Keep any unavailable fundamentals marked as unavailable instead of retrying the same failed provider calls.
|
|
21
|
-
- Use the
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
78
|
+
- Use the ${evidenceList} you already fetched to finish the comparison even if some fundamentals are missing.
|
|
79
|
+
- ${verdictInstruction}${horizonGuidance}${macroHedgeGuidance}${interestRateGuidance}${overlapGuidance}`,
|
|
80
|
+
{
|
|
81
|
+
requiredInputs: ["asset_data"],
|
|
82
|
+
expectedOutputs: ["comparison_summary"],
|
|
83
|
+
},
|
|
84
|
+
),
|
|
26
85
|
],
|
|
27
86
|
};
|
|
28
87
|
}
|
|
29
|
-
|
|
30
|
-
/** @deprecated Use buildCompareAssetsWorkflowDefinition instead */
|
|
31
|
-
export function buildCompareAssetsWorkflow(
|
|
32
|
-
resolution: SlotResolution<CompareAssetsSlots>,
|
|
33
|
-
): WorkflowPlan {
|
|
34
|
-
const def = buildCompareAssetsWorkflowDefinition(resolution);
|
|
35
|
-
return {
|
|
36
|
-
initialPrompt: def.steps[0].prompt,
|
|
37
|
-
followUps: def.steps.slice(1).map((s) => s.prompt),
|
|
38
|
-
};
|
|
39
|
-
}
|
package/src/workflows/index.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export type { WorkflowPlan } from "./types.js";
|
|
1
|
+
export { buildCompareAssetsWorkflowDefinition } from "./compare-assets.js";
|
|
2
|
+
export { buildOptionsScreenerWorkflowDefinition } from "./options-screener.js";
|
|
3
|
+
export { buildPortfolioWorkflowDefinition } from "./portfolio-builder.js";
|