opencandle 0.5.0 → 0.7.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/README.md +170 -186
- 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 +66 -7
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +13 -3
- package/dist/config.js +25 -5
- 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/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 +2 -3
- package/dist/infra/index.js +2 -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.js +12 -9
- 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.js +11 -11
- 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.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.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.d.ts +2 -2
- package/dist/onboarding/connect.js +13 -8
- 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/provider-status.d.ts +48 -0
- package/dist/onboarding/provider-status.js +285 -0
- package/dist/onboarding/provider-status.js.map +1 -0
- package/dist/onboarding/providers.d.ts +85 -8
- package/dist/onboarding/providers.js +83 -18
- package/dist/onboarding/providers.js.map +1 -1
- package/dist/onboarding/state.d.ts +1 -0
- package/dist/onboarding/state.js +5 -0
- 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.d.ts +12 -1
- package/dist/onboarding/tool-tags.js +37 -5
- package/dist/onboarding/tool-tags.js.map +1 -1
- package/dist/onboarding/validation.d.ts +2 -2
- 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 +502 -42
- 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 +8 -3
- package/dist/pi/setup.js.map +1 -1
- package/dist/pi/tool-adapter.d.ts +4 -1
- package/dist/pi/tool-adapter.js +10 -6
- package/dist/pi/tool-adapter.js.map +1 -1
- package/dist/prompts/context-builder.d.ts +1 -1
- package/dist/prompts/context-builder.js +20 -7
- package/dist/prompts/context-builder.js.map +1 -1
- package/dist/prompts/policy-cards.d.ts +1 -1
- package/dist/prompts/policy-cards.js +2 -2
- package/dist/prompts/policy-cards.js.map +1 -1
- package/dist/prompts/sections.d.ts +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 +54 -16
- package/dist/prompts/workflow-prompts.js.map +1 -1
- package/dist/providers/alpha-vantage.d.ts +1 -1
- package/dist/providers/alpha-vantage.js +26 -7
- 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/external-tool-error.d.ts +10 -0
- package/dist/providers/external-tool-error.js +21 -0
- package/dist/providers/external-tool-error.js.map +1 -0
- 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-cli.d.ts +36 -0
- package/dist/providers/reddit-cli.js +201 -0
- package/dist/providers/reddit-cli.js.map +1 -0
- package/dist/providers/reddit.d.ts +1 -1
- package/dist/providers/reddit.js +9 -37
- package/dist/providers/reddit.js.map +1 -1
- package/dist/providers/sec-edgar.d.ts +1 -0
- package/dist/providers/sec-edgar.js +12 -4
- 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-cli.d.ts +40 -0
- package/dist/providers/twitter-cli.js +153 -0
- package/dist/providers/twitter-cli.js.map +1 -0
- package/dist/providers/twitter.d.ts +0 -8
- package/dist/providers/twitter.js +8 -60
- 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 +44 -8
- package/dist/providers/wrap-provider.js.map +1 -1
- package/dist/providers/yahoo-finance.d.ts +1 -1
- package/dist/providers/yahoo-finance.js +153 -48
- package/dist/providers/yahoo-finance.js.map +1 -1
- package/dist/routing/classify-intent.d.ts +6 -0
- package/dist/routing/classify-intent.js +78 -7
- package/dist/routing/classify-intent.js.map +1 -1
- package/dist/routing/defaults.d.ts +1 -1
- package/dist/routing/entity-extractor.d.ts +1 -0
- package/dist/routing/entity-extractor.js +234 -29
- 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 +10 -10
- package/dist/routing/index.js +6 -6
- package/dist/routing/index.js.map +1 -1
- package/dist/routing/planning.d.ts +2 -2
- package/dist/routing/planning.js +65 -34
- package/dist/routing/planning.js.map +1 -1
- package/dist/routing/route-manifest.d.ts +2 -2
- package/dist/routing/route-manifest.js +25 -4
- package/dist/routing/route-manifest.js.map +1 -1
- package/dist/routing/router-llm-client.js.map +1 -1
- package/dist/routing/router-prompt.js +7 -9
- package/dist/routing/router-prompt.js.map +1 -1
- package/dist/routing/router-types.d.ts +1 -0
- package/dist/routing/router.js +137 -22
- package/dist/routing/router.js.map +1 -1
- package/dist/routing/slot-resolver.d.ts +1 -1
- package/dist/routing/slot-resolver.js +2 -4
- 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 +1 -1
- package/dist/routing/turn-context.js +1 -1
- package/dist/routing/turn-context.js.map +1 -1
- package/dist/routing/types.d.ts +2 -0
- package/dist/runtime/answer-contracts.d.ts +1 -1
- package/dist/runtime/answer-contracts.js +48 -9
- package/dist/runtime/answer-contracts.js.map +1 -1
- package/dist/runtime/artifact-contracts.js.map +1 -1
- package/dist/runtime/planning-evidence.js +47 -26
- package/dist/runtime/planning-evidence.js.map +1 -1
- 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 +13 -5
- package/dist/runtime/session-coordinator.js +160 -20
- 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 +7 -5
- 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 +10 -11
- package/dist/sentiment/index.js +10 -20
- package/dist/sentiment/index.js.map +1 -1
- package/dist/sentiment/insights.d.ts +17 -0
- package/dist/sentiment/insights.js +206 -0
- package/dist/sentiment/insights.js.map +1 -0
- 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 +14 -2
- package/dist/sentiment/pipeline.js.map +1 -1
- package/dist/sentiment/scorer.d.ts +2 -0
- package/dist/sentiment/scorer.js +11 -2
- package/dist/sentiment/scorer.js.map +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.d.ts +2 -0
- package/dist/sentiment/types.js.map +1 -1
- package/dist/system-prompt.js +6 -9
- 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 +11 -6
- package/dist/tools/fundamentals/company-overview.js.map +1 -1
- package/dist/tools/fundamentals/comps.js +18 -9
- package/dist/tools/fundamentals/comps.js.map +1 -1
- package/dist/tools/fundamentals/dcf.js +23 -11
- package/dist/tools/fundamentals/dcf.js.map +1 -1
- package/dist/tools/fundamentals/earnings.js +8 -3
- package/dist/tools/fundamentals/earnings.js.map +1 -1
- package/dist/tools/fundamentals/financials.js +8 -3
- package/dist/tools/fundamentals/financials.js.map +1 -1
- package/dist/tools/fundamentals/sec-filings.js +21 -6
- package/dist/tools/fundamentals/sec-filings.js.map +1 -1
- package/dist/tools/index.d.ts +27 -20
- package/dist/tools/index.js +55 -43
- 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/macro/fear-greed.js.map +1 -1
- package/dist/tools/macro/fred-data.d.ts +1 -1
- package/dist/tools/macro/fred-data.js +17 -6
- package/dist/tools/macro/fred-data.js.map +1 -1
- package/dist/tools/market/crypto-history.js +3 -1
- package/dist/tools/market/crypto-history.js.map +1 -1
- package/dist/tools/market/crypto-price.js +3 -1
- 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 +160 -8
- 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 +26 -7
- package/dist/tools/market/stock-history.js.map +1 -1
- package/dist/tools/market/stock-quote.js +5 -3
- package/dist/tools/market/stock-quote.js.map +1 -1
- package/dist/tools/options/greeks.js +1 -1
- package/dist/tools/options/greeks.js.map +1 -1
- package/dist/tools/options/option-chain.js +19 -6
- 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 +33 -13
- 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.js +10 -3
- package/dist/tools/portfolio/holdings-overlap.js.map +1 -1
- 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 +337 -87
- 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 +45 -6
- 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 +246 -101
- package/dist/tools/portfolio/tracker.js.map +1 -1
- package/dist/tools/portfolio/watchlist.d.ts +6 -4
- package/dist/tools/portfolio/watchlist.js +208 -108
- package/dist/tools/portfolio/watchlist.js.map +1 -1
- package/dist/tools/sentiment/insight-format.d.ts +2 -0
- package/dist/tools/sentiment/insight-format.js +36 -0
- package/dist/tools/sentiment/insight-format.js.map +1 -0
- package/dist/tools/sentiment/query-match.d.ts +3 -0
- package/dist/tools/sentiment/query-match.js +113 -0
- package/dist/tools/sentiment/query-match.js.map +1 -0
- package/dist/tools/sentiment/reddit-sentiment.d.ts +12 -1
- package/dist/tools/sentiment/reddit-sentiment.js +266 -107
- package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
- package/dist/tools/sentiment/sentiment-summary.d.ts +9 -1
- package/dist/tools/sentiment/sentiment-summary.js +223 -205
- 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.d.ts +11 -1
- package/dist/tools/sentiment/twitter-sentiment.js +188 -58
- 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 +9 -13
- package/dist/tools/sentiment/web-search.js.map +1 -1
- package/dist/tools/sentiment/web-sentiment.js +19 -3
- package/dist/tools/sentiment/web-sentiment.js.map +1 -1
- package/dist/tools/technical/backtest.d.ts +1 -1
- package/dist/tools/technical/backtest.js +27 -20
- package/dist/tools/technical/backtest.js.map +1 -1
- package/dist/tools/technical/indicators.js +23 -5
- 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/portfolio.d.ts +14 -4
- package/dist/types/sentiment.d.ts +52 -0
- package/dist/workflows/compare-assets.d.ts +0 -3
- package/dist/workflows/compare-assets.js +20 -11
- 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 +4 -11
- package/dist/workflows/options-screener.js.map +1 -1
- package/dist/workflows/portfolio-builder.d.ts +0 -3
- package/dist/workflows/portfolio-builder.js +0 -8
- package/dist/workflows/portfolio-builder.js.map +1 -1
- package/gui/server/ask-user-bridge.ts +1 -1
- 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/invoke-tool.ts +160 -3
- 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 +156 -2
- package/gui/server/private-api-access.ts +62 -0
- package/gui/server/projector.ts +18 -9
- package/gui/server/prompt-observation.ts +4 -7
- package/gui/server/quote-snapshot-store.ts +50 -0
- package/gui/server/server.ts +218 -451
- package/gui/server/session-actions.ts +186 -1
- package/gui/server/shutdown.ts +47 -0
- package/gui/server/tool-invoke-ack.ts +49 -0
- package/gui/server/tool-metadata.ts +101 -24
- package/gui/server/websocket.ts +13 -3
- package/gui/server/writer-lock.ts +6 -2
- package/gui/server/ws-hub.ts +311 -0
- package/gui/shared/chat-events.ts +16 -1
- package/gui/shared/event-reducer.ts +24 -6
- package/gui/web/dist/assets/CatalogOverlay-CgeY5Pkp.js +1 -0
- package/gui/web/dist/assets/index-C6W_2eAn.js +69 -0
- package/gui/web/dist/assets/index-hwbx24a5.css +1 -0
- package/gui/web/dist/index.html +2 -2
- package/package.json +9 -6
- package/src/analysts/contracts.ts +10 -23
- package/src/analysts/orchestrator.ts +8 -43
- package/src/cli.ts +76 -12
- package/src/config.ts +44 -9
- package/src/index.ts +1 -1
- package/src/infra/cache.ts +41 -30
- package/src/infra/http-client.ts +72 -6
- package/src/infra/index.ts +6 -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 +22 -19
- 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 +14 -16
- package/src/memory/retrieval.ts +8 -7
- package/src/memory/sqlite.ts +407 -6
- package/src/memory/storage.ts +5 -15
- package/src/memory/tool-defaults.ts +60 -39
- package/src/memory/types.ts +3 -3
- package/src/monitor.ts +121 -0
- package/src/onboarding/connect.ts +24 -31
- package/src/onboarding/credential-interceptor.ts +3 -15
- package/src/onboarding/degradation-accumulator.ts +1 -3
- package/src/onboarding/provider-status.ts +410 -0
- package/src/onboarding/providers.ts +144 -45
- package/src/onboarding/state.ts +13 -15
- package/src/onboarding/tool-helpers.ts +2 -9
- package/src/onboarding/tool-tags.ts +51 -8
- package/src/onboarding/validation.ts +16 -22
- package/src/pi/opencandle-extension.ts +643 -101
- package/src/pi/session.ts +7 -5
- package/src/pi/setup.ts +61 -43
- package/src/pi/tool-adapter.ts +19 -6
- package/src/prompts/context-builder.ts +24 -13
- package/src/prompts/policy-cards.ts +3 -3
- package/src/prompts/sections.ts +1 -1
- package/src/prompts/symbol-preflight.ts +80 -0
- package/src/prompts/workflow-prompts.ts +77 -28
- package/src/providers/alpha-vantage.ts +58 -39
- 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/external-tool-error.ts +20 -0
- 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-cli.ts +317 -0
- package/src/providers/reddit.ts +14 -59
- package/src/providers/sec-edgar.ts +20 -6
- package/src/providers/tradingview.ts +399 -0
- package/src/providers/twitter-cli.ts +233 -0
- package/src/providers/twitter.ts +8 -79
- package/src/providers/web-search.ts +30 -20
- package/src/providers/with-fallback.ts +8 -7
- package/src/providers/wrap-provider.ts +49 -10
- package/src/providers/yahoo-finance.ts +204 -66
- package/src/routing/classify-intent.ts +101 -10
- package/src/routing/defaults.ts +1 -1
- package/src/routing/entity-extractor.ts +287 -38
- package/src/routing/fund-symbols.ts +58 -0
- package/src/routing/horizon.ts +7 -0
- package/src/routing/index.ts +48 -48
- package/src/routing/planning.ts +145 -53
- package/src/routing/route-manifest.ts +37 -15
- package/src/routing/router-llm-client.ts +4 -4
- package/src/routing/router-prompt.ts +15 -19
- package/src/routing/router-types.ts +2 -5
- package/src/routing/router.ts +251 -53
- package/src/routing/slot-resolver.ts +34 -11
- package/src/routing/symbol-disambiguator.ts +72 -0
- package/src/routing/turn-context.ts +6 -9
- package/src/routing/types.ts +2 -0
- package/src/runtime/answer-contracts.ts +105 -45
- package/src/runtime/artifact-contracts.ts +2 -1
- package/src/runtime/planning-evidence.ts +157 -66
- package/src/runtime/prompt-step.ts +1 -16
- package/src/runtime/run-context.ts +12 -2
- package/src/runtime/session-coordinator.ts +238 -63
- package/src/runtime/session-title.ts +60 -0
- package/src/runtime/tool-defaults-wrapper.ts +13 -5
- 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 +17 -26
- package/src/sentiment/insights.ts +269 -0
- package/src/sentiment/keywords.ts +26 -4
- package/src/sentiment/pipeline.ts +28 -5
- package/src/sentiment/scorer.ts +13 -2
- package/src/sentiment/store.ts +2 -2
- package/src/sentiment/trends.ts +9 -3
- package/src/sentiment/types.ts +8 -4
- package/src/system-prompt.ts +6 -9
- package/src/tool-kit.ts +10 -9
- package/src/tools/fundamentals/company-overview.ts +19 -9
- package/src/tools/fundamentals/comps.ts +68 -55
- package/src/tools/fundamentals/dcf.ts +145 -95
- package/src/tools/fundamentals/earnings.ts +16 -6
- package/src/tools/fundamentals/financials.ts +16 -7
- package/src/tools/fundamentals/sec-filings.ts +37 -16
- package/src/tools/index.ts +56 -43
- package/src/tools/interaction/ask-user.ts +22 -10
- package/src/tools/macro/fear-greed.ts +1 -1
- package/src/tools/macro/fred-data.ts +58 -46
- package/src/tools/market/crypto-history.ts +8 -3
- package/src/tools/market/crypto-price.ts +6 -6
- package/src/tools/market/screen-stocks.ts +279 -0
- package/src/tools/market/search-ticker.ts +218 -17
- package/src/tools/market/stock-history.ts +37 -12
- package/src/tools/market/stock-quote.ts +10 -7
- package/src/tools/options/greeks.ts +5 -5
- package/src/tools/options/option-chain.ts +41 -17
- package/src/tools/portfolio/alerts.ts +457 -0
- package/src/tools/portfolio/correlation.ts +47 -20
- package/src/tools/portfolio/daily-report.ts +101 -0
- package/src/tools/portfolio/holdings-overlap.ts +31 -15
- package/src/tools/portfolio/notifications.ts +45 -0
- package/src/tools/portfolio/predictions.ts +406 -106
- package/src/tools/portfolio/risk-analysis.ts +46 -7
- package/src/tools/portfolio/tracker.ts +270 -109
- package/src/tools/portfolio/watchlist.ts +250 -121
- package/src/tools/sentiment/insight-format.ts +50 -0
- package/src/tools/sentiment/query-match.ts +117 -0
- package/src/tools/sentiment/reddit-sentiment.ts +360 -121
- package/src/tools/sentiment/sentiment-summary.ts +302 -235
- package/src/tools/sentiment/sentiment-trend.ts +24 -7
- package/src/tools/sentiment/twitter-sentiment.ts +264 -73
- package/src/tools/sentiment/untrusted-text.ts +21 -0
- package/src/tools/sentiment/web-search.ts +21 -18
- package/src/tools/sentiment/web-sentiment.ts +30 -10
- package/src/tools/technical/backtest.ts +32 -22
- package/src/tools/technical/indicators.ts +39 -14
- package/src/types/index.ts +8 -3
- package/src/types/market.ts +1 -0
- package/src/types/portfolio.ts +14 -4
- package/src/types/sentiment.ts +61 -2
- package/src/workflows/compare-assets.ts +33 -21
- package/src/workflows/index.ts +3 -4
- package/src/workflows/options-screener.ts +27 -29
- package/src/workflows/portfolio-builder.ts +34 -27
- package/dist/infra/browser.d.ts +0 -35
- package/dist/infra/browser.js +0 -103
- package/dist/infra/browser.js.map +0 -1
- package/dist/tools/interaction/twitter-login.d.ts +0 -8
- package/dist/tools/interaction/twitter-login.js +0 -77
- package/dist/tools/interaction/twitter-login.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-Bmp6Knu7.js +0 -1
- package/gui/web/dist/assets/index-Bxt9QpLX.css +0 -1
- package/gui/web/dist/assets/index-CZ9DHZYy.js +0 -67
- package/src/infra/browser.ts +0 -111
- package/src/tools/interaction/twitter-login.ts +0 -93
- package/src/workflows/types.ts +0 -4
|
@@ -1,9 +1,9 @@
|
|
|
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
8
|
export type Strategy = "sma_crossover" | "sma_50_200_crossover" | "rsi_mean_reversion";
|
|
9
9
|
|
|
@@ -61,7 +61,7 @@ function backtestSMACrossover(
|
|
|
61
61
|
const sLong = longSma[i];
|
|
62
62
|
const price = closes[barIdx];
|
|
63
63
|
|
|
64
|
-
if (!position && sShort > sLong) {
|
|
64
|
+
if (!position && sShort > sLong && price > 0) {
|
|
65
65
|
// Buy signal
|
|
66
66
|
position = true;
|
|
67
67
|
entryPrice = price;
|
|
@@ -75,9 +75,7 @@ function backtestSMACrossover(
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// Track mark-to-market equity for accurate drawdown
|
|
78
|
-
const currentEquity = position
|
|
79
|
-
? equity * (1 + (price - entryPrice) / entryPrice)
|
|
80
|
-
: equity;
|
|
78
|
+
const currentEquity = position ? equity * (1 + (price - entryPrice) / entryPrice) : equity;
|
|
81
79
|
if (currentEquity > peak) peak = currentEquity;
|
|
82
80
|
const dd = (peak - currentEquity) / peak;
|
|
83
81
|
if (dd > maxDd) maxDd = dd;
|
|
@@ -115,7 +113,7 @@ function backtestRSIMeanReversion(bars: OHLCV[], closes: number[]): BacktestResu
|
|
|
115
113
|
const r = rsi[i];
|
|
116
114
|
const price = closes[barIdx];
|
|
117
115
|
|
|
118
|
-
if (!position && r < 30) {
|
|
116
|
+
if (!position && r < 30 && price > 0) {
|
|
119
117
|
// RSI oversold → buy
|
|
120
118
|
position = true;
|
|
121
119
|
entryPrice = price;
|
|
@@ -129,9 +127,7 @@ function backtestRSIMeanReversion(bars: OHLCV[], closes: number[]): BacktestResu
|
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
// Track mark-to-market equity for accurate drawdown
|
|
132
|
-
const currentEquity = position
|
|
133
|
-
? equity * (1 + (price - entryPrice) / entryPrice)
|
|
134
|
-
: equity;
|
|
130
|
+
const currentEquity = position ? equity * (1 + (price - entryPrice) / entryPrice) : equity;
|
|
135
131
|
if (currentEquity > peak) peak = currentEquity;
|
|
136
132
|
const dd = (peak - currentEquity) / peak;
|
|
137
133
|
if (dd > maxDd) maxDd = dd;
|
|
@@ -157,9 +153,8 @@ function buildResult(
|
|
|
157
153
|
): BacktestResult {
|
|
158
154
|
const sellTrades = tradeLog.filter((t) => t.type === "sell" && t.pnl != null);
|
|
159
155
|
const wins = sellTrades.filter((t) => t.pnl! > 0).length;
|
|
160
|
-
const buyAndHoldReturn =
|
|
161
|
-
? (closes[closes.length - 1] - closes[0]) / closes[0]
|
|
162
|
-
: 0;
|
|
156
|
+
const buyAndHoldReturn =
|
|
157
|
+
closes.length > 1 && closes[0] > 0 ? (closes[closes.length - 1] - closes[0]) / closes[0] : 0;
|
|
163
158
|
|
|
164
159
|
return {
|
|
165
160
|
strategy,
|
|
@@ -177,9 +172,8 @@ function emptyResult(strategy: string, closes: number[]): BacktestResult {
|
|
|
177
172
|
return {
|
|
178
173
|
strategy,
|
|
179
174
|
totalReturn: 0,
|
|
180
|
-
buyAndHoldReturn:
|
|
181
|
-
? (closes[closes.length - 1] - closes[0]) / closes[0]
|
|
182
|
-
: 0,
|
|
175
|
+
buyAndHoldReturn:
|
|
176
|
+
closes.length > 1 && closes[0] > 0 ? (closes[closes.length - 1] - closes[0]) / closes[0] : 0,
|
|
183
177
|
trades: 0,
|
|
184
178
|
wins: 0,
|
|
185
179
|
winRate: 0,
|
|
@@ -191,11 +185,20 @@ function emptyResult(strategy: string, closes: number[]): BacktestResult {
|
|
|
191
185
|
const params = Type.Object({
|
|
192
186
|
symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, MSFT, SPY)" }),
|
|
193
187
|
strategy: Type.Union(
|
|
194
|
-
[
|
|
195
|
-
|
|
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
|
+
},
|
|
196
197
|
),
|
|
197
198
|
period: Type.Optional(
|
|
198
|
-
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
|
+
}),
|
|
199
202
|
),
|
|
200
203
|
});
|
|
201
204
|
|
|
@@ -211,7 +214,9 @@ export const backtestTool: AgentTool<typeof params> = {
|
|
|
211
214
|
const historyResult = await wrapProvider("yahoo", () => getHistory(symbol, period, "1d"));
|
|
212
215
|
if (historyResult.status === "unavailable") {
|
|
213
216
|
return {
|
|
214
|
-
content: [
|
|
217
|
+
content: [
|
|
218
|
+
{ type: "text", text: `⚠ Backtest unavailable for ${symbol} (${historyResult.reason}).` },
|
|
219
|
+
],
|
|
215
220
|
details: null as any,
|
|
216
221
|
};
|
|
217
222
|
}
|
|
@@ -220,7 +225,12 @@ export const backtestTool: AgentTool<typeof params> = {
|
|
|
220
225
|
const minBars = requiredBarsForStrategy(args.strategy);
|
|
221
226
|
if (bars.length < minBars) {
|
|
222
227
|
return {
|
|
223
|
-
content: [
|
|
228
|
+
content: [
|
|
229
|
+
{
|
|
230
|
+
type: "text",
|
|
231
|
+
text: `Insufficient data for backtesting ${symbol} (need ${minBars}+ days, got ${bars.length})`,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
224
234
|
details: null,
|
|
225
235
|
};
|
|
226
236
|
}
|
|
@@ -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 ---
|
|
@@ -52,7 +52,12 @@ export const technicalIndicatorsTool: AgentTool<typeof params> = {
|
|
|
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,7 +66,12 @@ 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
|
}
|
|
@@ -79,9 +89,12 @@ export const technicalIndicatorsTool: AgentTool<typeof params> = {
|
|
|
79
89
|
const latestMacd = macd[macd.length - 1];
|
|
80
90
|
const latestBB = bb[bb.length - 1];
|
|
81
91
|
const latestVwap = vwap[vwap.length - 1];
|
|
82
|
-
const obvTrend =
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
const obvTrend =
|
|
93
|
+
obv.length >= 20
|
|
94
|
+
? obv[obv.length - 1] > obv[obv.length - 20]
|
|
95
|
+
? "Rising"
|
|
96
|
+
: "Falling"
|
|
97
|
+
: "N/A";
|
|
85
98
|
|
|
86
99
|
const lines = [
|
|
87
100
|
`**${symbol} Technical Analysis** (${bars[0].date} to ${bars[bars.length - 1].date})`,
|
|
@@ -103,7 +116,13 @@ export const technicalIndicatorsTool: AgentTool<typeof params> = {
|
|
|
103
116
|
range,
|
|
104
117
|
prices: closes,
|
|
105
118
|
dates: bars.map((b) => b.date),
|
|
106
|
-
sma20,
|
|
119
|
+
sma20,
|
|
120
|
+
sma50,
|
|
121
|
+
rsi,
|
|
122
|
+
macd,
|
|
123
|
+
bb,
|
|
124
|
+
obv,
|
|
125
|
+
vwap,
|
|
107
126
|
},
|
|
108
127
|
};
|
|
109
128
|
},
|
|
@@ -241,16 +260,22 @@ function trendSummary(
|
|
|
241
260
|
|
|
242
261
|
if (latestSma20 && price > latestSma20) signals.push("Price above SMA(20) — short-term bullish");
|
|
243
262
|
if (latestSma20 && price < latestSma20) signals.push("Price below SMA(20) — short-term bearish");
|
|
244
|
-
if (latestSma20 && latestSma50 && latestSma20 > latestSma50)
|
|
245
|
-
|
|
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)");
|
|
246
267
|
if (rsi != null && rsi >= 70) signals.push("RSI overbought — potential reversal");
|
|
247
268
|
if (rsi != null && rsi <= 30) signals.push("RSI oversold — potential bounce");
|
|
248
269
|
if (macd && macd.histogram > 0) signals.push("MACD bullish (histogram positive)");
|
|
249
270
|
if (macd && macd.histogram < 0) signals.push("MACD bearish (histogram negative)");
|
|
250
|
-
if (obvTrend === "Rising" && price > (latestSma20 ?? 0))
|
|
251
|
-
|
|
252
|
-
if (
|
|
253
|
-
|
|
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");
|
|
254
279
|
|
|
255
280
|
return signals.length > 0 ? "Signals: " + signals.join(" | ") : "No strong signals";
|
|
256
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/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 {
|
package/src/types/sentiment.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { SentinelRecord } from "../sentiment/types.js";
|
|
2
|
+
|
|
1
3
|
export interface FearGreedData {
|
|
2
4
|
value: number;
|
|
3
5
|
label: string; // "Extreme Fear" | "Fear" | "Neutral" | "Greed" | "Extreme Greed"
|
|
@@ -19,15 +21,70 @@ export interface TwitterTweet {
|
|
|
19
21
|
created: string;
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
export type SentimentInsightMethod = "deterministic-keyword-v1" | "llm";
|
|
25
|
+
export type SentimentConfidenceLevel = "low" | "medium" | "high";
|
|
26
|
+
|
|
27
|
+
export interface SentimentInsightConfidence {
|
|
28
|
+
level: SentimentConfidenceLevel;
|
|
29
|
+
score: number; // 0.0 to 1.0
|
|
30
|
+
reasons: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface SentimentInsightDriver {
|
|
34
|
+
label: string;
|
|
35
|
+
count: number;
|
|
36
|
+
polarity: "positive" | "negative" | "mixed";
|
|
37
|
+
terms: string[];
|
|
38
|
+
sourceIds: string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface SentimentRepresentativeItem {
|
|
42
|
+
source: "twitter" | "reddit" | "web" | "finnhub" | "aggregate";
|
|
43
|
+
sourceId: string;
|
|
44
|
+
title: string | null;
|
|
45
|
+
excerpt: string;
|
|
46
|
+
url: string | null;
|
|
47
|
+
author: string | null;
|
|
48
|
+
publishedAt: string | null;
|
|
49
|
+
engagement: number | null;
|
|
50
|
+
score: number;
|
|
51
|
+
matchedTerms: string[];
|
|
52
|
+
metadata?: Record<string, unknown>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface SentimentSourceCoverage {
|
|
56
|
+
sources: string[];
|
|
57
|
+
counts: Record<string, number>;
|
|
58
|
+
missingSources?: string[];
|
|
59
|
+
notes?: string[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface SentimentInsight {
|
|
63
|
+
label: string;
|
|
64
|
+
score: number;
|
|
65
|
+
sampleSize: number;
|
|
66
|
+
scoredSampleSize: number;
|
|
67
|
+
confidence: SentimentInsightConfidence;
|
|
68
|
+
positiveDrivers: SentimentInsightDriver[];
|
|
69
|
+
negativeDrivers: SentimentInsightDriver[];
|
|
70
|
+
mixedDrivers: SentimentInsightDriver[];
|
|
71
|
+
notableClaims: string[];
|
|
72
|
+
representativeItems: SentimentRepresentativeItem[];
|
|
73
|
+
sourceCoverage: SentimentSourceCoverage;
|
|
74
|
+
caveats: string[];
|
|
75
|
+
method: SentimentInsightMethod;
|
|
76
|
+
}
|
|
77
|
+
|
|
22
78
|
export interface TwitterSentimentResult {
|
|
23
79
|
query: string;
|
|
24
80
|
tweetCount: number;
|
|
25
81
|
tweets: TwitterTweet[];
|
|
26
|
-
sentimentScore: number;
|
|
82
|
+
sentimentScore: number; // -1.0 (fully bearish) to +1.0 (fully bullish)
|
|
27
83
|
bullishCount: number;
|
|
28
84
|
bearishCount: number;
|
|
29
85
|
topMentions: string[];
|
|
30
86
|
fetchedAt: string;
|
|
87
|
+
insight?: SentimentInsight;
|
|
31
88
|
}
|
|
32
89
|
|
|
33
90
|
export interface WebSearchResult {
|
|
@@ -63,8 +120,10 @@ export interface RedditSentimentResult {
|
|
|
63
120
|
created: string;
|
|
64
121
|
}>;
|
|
65
122
|
topMentions: string[];
|
|
66
|
-
sentimentScore: number;
|
|
123
|
+
sentimentScore: number; // -1.0 (fully bearish) to +1.0 (fully bullish)
|
|
67
124
|
bullishCount: number;
|
|
68
125
|
bearishCount: number;
|
|
69
126
|
fetchedAt: string;
|
|
127
|
+
insight?: SentimentInsight;
|
|
128
|
+
records?: SentinelRecord[];
|
|
70
129
|
}
|
|
@@ -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
|
|
|
@@ -12,11 +13,18 @@ export function buildCompareAssetsWorkflowDefinition(
|
|
|
12
13
|
const isMacroHedge = resolution.resolved.metrics?.includes("macro_hedge") ?? false;
|
|
13
14
|
const isInterestRateSensitive = resolution.resolved.metrics?.includes("interest_rates") ?? false;
|
|
14
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;
|
|
15
21
|
const evidenceList = resolution.resolved.metrics?.includes("sentiment")
|
|
16
22
|
? "price, technical, risk, and sentiment data"
|
|
17
23
|
: isOverlapComparison
|
|
18
24
|
? "quote, holdings-overlap, and correlation data"
|
|
19
|
-
|
|
25
|
+
: shouldProbeFundOverlap
|
|
26
|
+
? "price, technical, risk, correlation, and holdings-overlap data when applicable"
|
|
27
|
+
: "price, technical, and risk data";
|
|
20
28
|
const horizonGuidance = timeHorizon
|
|
21
29
|
? `
|
|
22
30
|
- Start by directly answering whether these assets are reasonable to compare for a ${timeHorizon} horizon.
|
|
@@ -40,10 +48,20 @@ export function buildCompareAssetsWorkflowDefinition(
|
|
|
40
48
|
- For ETF overlap prompts, synthesize the holdings-overlap and shared-exposure evidence first, with correlation only as supporting diversification context.
|
|
41
49
|
- State the diversification implication directly: deliberate factor tilt, accidental duplication, or genuinely differentiated exposure.
|
|
42
50
|
- If provider holdings coverage was partial or unavailable, say that before giving the practical next step.`
|
|
43
|
-
:
|
|
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
|
+
: "";
|
|
44
58
|
const verdictInstruction = isOverlapComparison
|
|
45
59
|
? "End with a concise verdict on whether the added fund improves diversification or mostly duplicates existing exposure."
|
|
46
|
-
:
|
|
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.";
|
|
47
65
|
|
|
48
66
|
return {
|
|
49
67
|
workflowType: "compare_assets",
|
|
@@ -52,24 +70,18 @@ export function buildCompareAssetsWorkflowDefinition(
|
|
|
52
70
|
requiredInputs: ["symbols"],
|
|
53
71
|
expectedOutputs: ["asset_data"],
|
|
54
72
|
}),
|
|
55
|
-
promptStep(
|
|
73
|
+
promptStep(
|
|
74
|
+
"compare_and_present",
|
|
75
|
+
"Present side-by-side comparison",
|
|
76
|
+
`Now present the side-by-side comparison for ${symbols}:
|
|
56
77
|
- Keep any unavailable fundamentals marked as unavailable instead of retrying the same failed provider calls.
|
|
57
78
|
- Use the ${evidenceList} you already fetched to finish the comparison even if some fundamentals are missing.
|
|
58
|
-
- ${verdictInstruction}${horizonGuidance}${macroHedgeGuidance}${interestRateGuidance}${overlapGuidance}`,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
79
|
+
- ${verdictInstruction}${horizonGuidance}${macroHedgeGuidance}${interestRateGuidance}${overlapGuidance}`,
|
|
80
|
+
{
|
|
81
|
+
requiredInputs: ["asset_data"],
|
|
82
|
+
expectedOutputs: ["comparison_summary"],
|
|
83
|
+
},
|
|
84
|
+
),
|
|
62
85
|
],
|
|
63
86
|
};
|
|
64
87
|
}
|
|
65
|
-
|
|
66
|
-
/** @deprecated Use buildCompareAssetsWorkflowDefinition instead */
|
|
67
|
-
export function buildCompareAssetsWorkflow(
|
|
68
|
-
resolution: SlotResolution<CompareAssetsSlots>,
|
|
69
|
-
): WorkflowPlan {
|
|
70
|
-
const def = buildCompareAssetsWorkflowDefinition(resolution);
|
|
71
|
-
return {
|
|
72
|
-
initialPrompt: def.steps[0].prompt,
|
|
73
|
-
followUps: def.steps.slice(1).map((s) => s.prompt),
|
|
74
|
-
};
|
|
75
|
-
}
|
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";
|
|
@@ -1,32 +1,34 @@
|
|
|
1
|
-
import type { OptionsScreenerSlots, SlotResolution } from "../routing/types.js";
|
|
2
1
|
import { buildOptionsScreenerPrompt } from "../prompts/workflow-prompts.js";
|
|
3
|
-
import type {
|
|
2
|
+
import type { OptionsScreenerSlots, SlotResolution } from "../routing/types.js";
|
|
4
3
|
import type { WorkflowDefinition } from "../runtime/prompt-step.js";
|
|
5
4
|
import { promptStep } from "../runtime/prompt-step.js";
|
|
6
5
|
|
|
7
|
-
export function buildOptionsScreenerWorkflowDefinition(
|
|
6
|
+
export function buildOptionsScreenerWorkflowDefinition(
|
|
7
|
+
resolution: SlotResolution<OptionsScreenerSlots>,
|
|
8
|
+
): WorkflowDefinition {
|
|
8
9
|
const s = resolution.resolved;
|
|
9
10
|
const isProtectivePutContext = s.optionStrategy === "protective_put";
|
|
10
11
|
const contractType = s.direction === "bullish" && !isProtectivePutContext ? "calls" : "puts";
|
|
11
12
|
const horizonPhrase = describeDteTarget(s.dteTarget);
|
|
12
|
-
const isCoveredCallContext =
|
|
13
|
-
|
|
14
|
-
s.
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const isCoveredCallContext =
|
|
14
|
+
!isProtectivePutContext &&
|
|
15
|
+
(s.optionStrategy === "covered_call" ||
|
|
16
|
+
s.costBasis !== undefined ||
|
|
17
|
+
(s.catalystSymbols?.length ?? 0) > 0);
|
|
17
18
|
const rankingInstruction = isProtectivePutContext
|
|
18
19
|
? "Rank by protection per dollar of premium, expiration fit, moneyness, hedge floor, live liquidity, and premium as a percent of the stock position."
|
|
19
20
|
: isCoveredCallContext
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const maxPremiumInstruction =
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
? "Rank by premium collected, strike above cost basis, assignment risk, event risk, live liquidity, and probability of expiring out of the money."
|
|
22
|
+
: `Rank by ${s.objective}: balance premium cost, delta exposure, and probability of profit. Only include contracts with |delta| >= 0.20.`;
|
|
23
|
+
const maxPremiumInstruction =
|
|
24
|
+
s.maxPremium !== undefined
|
|
25
|
+
? ` Do not rank contracts above the user's max premium of $${s.maxPremium.toLocaleString("en-US")} unless no contracts under that cap are liquid; if so, say the cap could not be met.`
|
|
26
|
+
: "";
|
|
25
27
|
const riskInstruction = isProtectivePutContext
|
|
26
28
|
? "Include protective-put hedge risks: premium decay/cost, imperfect hedge before the strike, liquidity, and opportunity cost. Long protective puts do not have short-option assignment risk."
|
|
27
29
|
: isCoveredCallContext
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
? "Include covered-call sale risks: assignment risk, upside is capped at the strike plus premium, share-price downside in the owned stock less premium received, IV/event risk, and exit liquidity. Do not say max loss = premium or describe max loss as the option premium paid."
|
|
31
|
+
: "Include risk caveats: max loss = premium, IV crush risk, time decay (theta).";
|
|
30
32
|
const coveredCallFallback = isCoveredCallContext
|
|
31
33
|
? `
|
|
32
34
|
Covered-call fallback:
|
|
@@ -77,7 +79,10 @@ Protective-put requirements:
|
|
|
77
79
|
requiredInputs: ["symbol"],
|
|
78
80
|
expectedOutputs: ["option_chain"],
|
|
79
81
|
}),
|
|
80
|
-
promptStep(
|
|
82
|
+
promptStep(
|
|
83
|
+
"rank_and_present",
|
|
84
|
+
"Rank and present top contracts",
|
|
85
|
+
`Now rank and present the top ${contractType} for ${s.symbol}. You MUST produce a final text response — never end this turn with only tool calls.
|
|
81
86
|
|
|
82
87
|
1. From the option chain data already fetched, select the top 3-5 contracts matching: ${s.moneynessPreference} strikes, DTE near ${s.dteTarget}, with ${s.liquidityMinimum}.
|
|
83
88
|
2. ${rankingInstruction}${maxPremiumInstruction}
|
|
@@ -97,10 +102,12 @@ ${protectivePutFallback}
|
|
|
97
102
|
Length constraints:
|
|
98
103
|
- Max 1 sentence explaining the #1 pick.
|
|
99
104
|
- Risk section: max 3 bullets.
|
|
100
|
-
- Keep total response under 30 lines.`,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
- Keep total response under 30 lines.`,
|
|
106
|
+
{
|
|
107
|
+
requiredInputs: ["option_chain"],
|
|
108
|
+
expectedOutputs: ["ranked_contracts"],
|
|
109
|
+
},
|
|
110
|
+
),
|
|
104
111
|
],
|
|
105
112
|
};
|
|
106
113
|
}
|
|
@@ -116,12 +123,3 @@ function describeDteTarget(dteTarget: string): string {
|
|
|
116
123
|
if (plus) return `${plus[1]}+ day horizon`;
|
|
117
124
|
return `${dteTarget} horizon`;
|
|
118
125
|
}
|
|
119
|
-
|
|
120
|
-
/** @deprecated Use buildOptionsScreenerWorkflowDefinition instead */
|
|
121
|
-
export function buildOptionsScreenerWorkflow(resolution: SlotResolution<OptionsScreenerSlots>): WorkflowPlan {
|
|
122
|
-
const def = buildOptionsScreenerWorkflowDefinition(resolution);
|
|
123
|
-
return {
|
|
124
|
-
initialPrompt: def.steps[0].prompt,
|
|
125
|
-
followUps: def.steps.slice(1).map((s) => s.prompt),
|
|
126
|
-
};
|
|
127
|
-
}
|
|
@@ -1,30 +1,44 @@
|
|
|
1
|
-
import type { PortfolioSlots, SlotResolution } from "../routing/types.js";
|
|
2
1
|
import { buildPortfolioPrompt } from "../prompts/workflow-prompts.js";
|
|
3
|
-
import type {
|
|
2
|
+
import type { PortfolioSlots, SlotResolution } from "../routing/types.js";
|
|
4
3
|
import type { WorkflowDefinition } from "../runtime/prompt-step.js";
|
|
5
4
|
import { promptStep } from "../runtime/prompt-step.js";
|
|
6
5
|
|
|
7
|
-
export function buildPortfolioWorkflowDefinition(
|
|
6
|
+
export function buildPortfolioWorkflowDefinition(
|
|
7
|
+
resolution: SlotResolution<PortfolioSlots>,
|
|
8
|
+
): WorkflowDefinition {
|
|
8
9
|
const s = resolution.resolved;
|
|
9
10
|
|
|
10
11
|
return {
|
|
11
12
|
workflowType: "portfolio_builder",
|
|
12
13
|
steps: [
|
|
13
|
-
promptStep(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
promptStep(
|
|
15
|
+
"fetch_candidates",
|
|
16
|
+
"Fetch market data and select candidates",
|
|
17
|
+
buildPortfolioPrompt(resolution),
|
|
18
|
+
{
|
|
19
|
+
requiredInputs: ["symbols"],
|
|
20
|
+
expectedOutputs: ["candidate_positions"],
|
|
21
|
+
},
|
|
22
|
+
),
|
|
23
|
+
promptStep(
|
|
24
|
+
"risk_review",
|
|
25
|
+
"Review risk and diversification",
|
|
26
|
+
`Now review the risk and diversification of this draft portfolio:
|
|
18
27
|
1. Use analyze_correlation across all ${s.positionCount} candidates to check for concentration risk.
|
|
19
28
|
2. Use analyze_risk on each position for volatility and max drawdown.
|
|
20
29
|
3. If correlation is too high (>0.7 between any pair), suggest a replacement to improve diversification.
|
|
21
30
|
4. If any position's risk metrics undermine its intended role, lower its allocation, replace it with a role-equivalent candidate, or explicitly justify why it remains.
|
|
22
|
-
5. Confirm the portfolio fits a ${s.riskProfile} risk profile with ${s.timeHorizon} horizon.`,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
5. Confirm the portfolio fits a ${s.riskProfile} risk profile with ${s.timeHorizon} horizon.`,
|
|
32
|
+
{
|
|
33
|
+
skippable: true,
|
|
34
|
+
requiredInputs: ["candidate_positions"],
|
|
35
|
+
expectedOutputs: ["risk_assessment"],
|
|
36
|
+
},
|
|
37
|
+
),
|
|
38
|
+
promptStep(
|
|
39
|
+
"synthesize",
|
|
40
|
+
"Present final portfolio draft",
|
|
41
|
+
`Present the final portfolio draft as a structured summary:
|
|
28
42
|
- State all assumptions at the top (which parameters were defaults vs user-specified vs saved preferences).
|
|
29
43
|
- Commit to the allocation: concrete percentages per position, not ranges.
|
|
30
44
|
- Present an allocation table: symbol, allocation %, dollar amount ($${s.budget.toLocaleString("en-US")} total), current price used, estimated shares, role, and one-line analyst rationale per position.
|
|
@@ -38,19 +52,12 @@ Length constraints:
|
|
|
38
52
|
- Risk summary: max 3 bullet points.
|
|
39
53
|
- Implementation notes: max 3 bullets.
|
|
40
54
|
- Growth/safety suggestions: max 2 bullet points each.
|
|
41
|
-
- Keep total response under 40 lines.`,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
55
|
+
- Keep total response under 40 lines.`,
|
|
56
|
+
{
|
|
57
|
+
requiredInputs: ["risk_assessment"],
|
|
58
|
+
expectedOutputs: ["portfolio_summary"],
|
|
59
|
+
},
|
|
60
|
+
),
|
|
45
61
|
],
|
|
46
62
|
};
|
|
47
63
|
}
|
|
48
|
-
|
|
49
|
-
/** @deprecated Use buildPortfolioWorkflowDefinition instead */
|
|
50
|
-
export function buildPortfolioWorkflow(resolution: SlotResolution<PortfolioSlots>): WorkflowPlan {
|
|
51
|
-
const def = buildPortfolioWorkflowDefinition(resolution);
|
|
52
|
-
return {
|
|
53
|
-
initialPrompt: def.steps[0].prompt,
|
|
54
|
-
followUps: def.steps.slice(1).map((s) => s.prompt),
|
|
55
|
-
};
|
|
56
|
-
}
|