opencandle 0.5.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/README.md +164 -187
- 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 +30 -7
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +3 -3
- package/dist/config.js +12 -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/browser.js +3 -1
- 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.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.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 +412 -28
- 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.js +5 -2
- package/dist/pi/tool-adapter.js.map +1 -1
- package/dist/prompts/context-builder.d.ts +1 -1
- package/dist/prompts/context-builder.js +19 -6
- package/dist/prompts/context-builder.js.map +1 -1
- package/dist/prompts/policy-cards.d.ts +1 -1
- package/dist/prompts/policy-cards.js +1 -1
- 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/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 +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.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 +1 -1
- package/dist/providers/yahoo-finance.js +101 -17
- 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 +1 -1
- 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.js +36 -8
- 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 +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 +3 -2
- 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 +23 -19
- package/dist/tools/index.js +51 -39
- 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.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/reddit-sentiment.js +23 -10
- package/dist/tools/sentiment/reddit-sentiment.js.map +1 -1
- package/dist/tools/sentiment/sentiment-summary.js +15 -13
- 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 +12 -5
- 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 +15 -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/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 +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 +12 -7
- package/gui/server/prompt-observation.ts +4 -7
- package/gui/server/quote-snapshot-store.ts +50 -0
- package/gui/server/server.ts +200 -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 +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 +5 -1
- package/src/analysts/contracts.ts +10 -23
- package/src/analysts/orchestrator.ts +8 -43
- package/src/cli.ts +35 -12
- package/src/config.ts +17 -9
- package/src/index.ts +1 -1
- package/src/infra/browser.ts +3 -1
- 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 +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 +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 +529 -85
- package/src/pi/session.ts +7 -5
- package/src/pi/setup.ts +61 -43
- package/src/pi/tool-adapter.ts +5 -2
- package/src/prompts/context-builder.ts +23 -12
- package/src/prompts/policy-cards.ts +2 -2
- 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/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 +20 -6
- 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 +140 -35
- 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 +144 -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 +82 -43
- 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 +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 +3 -2
- 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 +51 -39
- 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 +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/reddit-sentiment.ts +50 -24
- package/src/tools/sentiment/sentiment-summary.ts +62 -41
- package/src/tools/sentiment/sentiment-trend.ts +24 -7
- package/src/tools/sentiment/twitter-sentiment.ts +22 -15
- 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 +26 -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 +2 -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/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/workflows/types.ts +0 -4
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
-
import { getOptionsChain } from "../../providers/yahoo-finance.js";
|
|
3
2
|
import { wrapProvider } from "../../providers/wrap-provider.js";
|
|
3
|
+
import { getOptionsChain } from "../../providers/yahoo-finance.js";
|
|
4
4
|
const params = Type.Object({
|
|
5
5
|
symbol: Type.String({ description: "Stock ticker symbol (e.g. AAPL, TSLA, SPY, MSFT)" }),
|
|
6
6
|
expiration: Type.Optional(Type.String({
|
|
7
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
7
8
|
description: "Expiration date as YYYY-MM-DD. If omitted, uses the nearest expiration.",
|
|
8
9
|
})),
|
|
9
10
|
type: Type.Optional(Type.Union([Type.Literal("call"), Type.Literal("put"), Type.Literal("CALL"), Type.Literal("PUT")], {
|
|
@@ -18,13 +19,13 @@ export const optionChainTool = {
|
|
|
18
19
|
async execute(_toolCallId, args) {
|
|
19
20
|
const symbol = args.symbol.toUpperCase();
|
|
20
21
|
const normalizedType = args.type?.toLowerCase();
|
|
21
|
-
const expirationTs = args.expiration
|
|
22
|
-
? Math.floor(new Date(args.expiration).getTime() / 1000)
|
|
23
|
-
: undefined;
|
|
22
|
+
const expirationTs = args.expiration ? parseExpiration(args.expiration) : undefined;
|
|
24
23
|
const result = await wrapProvider("yahoo", () => getOptionsChain(symbol, expirationTs));
|
|
25
24
|
if (result.status === "unavailable") {
|
|
26
25
|
return {
|
|
27
|
-
content: [
|
|
26
|
+
content: [
|
|
27
|
+
{ type: "text", text: `⚠ Options chain unavailable for ${symbol} (${result.reason}).` },
|
|
28
|
+
],
|
|
28
29
|
details: null,
|
|
29
30
|
};
|
|
30
31
|
}
|
|
@@ -35,7 +36,9 @@ export const optionChainTool = {
|
|
|
35
36
|
`Quote status: ${chain.quoteStatus.marketSession} / ${chain.quoteStatus.bidAskState}`,
|
|
36
37
|
"Option bid/ask and last prices are quoted per share; multiply by 100 for one standard contract premium.",
|
|
37
38
|
...(chain.quoteStatus.warning
|
|
38
|
-
? [
|
|
39
|
+
? [
|
|
40
|
+
`⚠ ${chain.quoteStatus.warning} do not treat zero bid/ask as confirmed live illiquidity without broker verification; do not stop at the stale quote caveat. Disclose the gap, avoid naming tradable live premiums, and finish the strategy explanation with mechanics, assignment outcomes, labeled hypotheticals, and what live broker quotes would change.`,
|
|
41
|
+
]
|
|
39
42
|
: []),
|
|
40
43
|
`Available expirations: ${formatAvailableExpirations(chain.expirationDates)}`,
|
|
41
44
|
"",
|
|
@@ -64,6 +67,16 @@ export const optionChainTool = {
|
|
|
64
67
|
return { content: [{ type: "text", text: lines.join("\n") }], details: chain };
|
|
65
68
|
},
|
|
66
69
|
};
|
|
70
|
+
function parseExpiration(expiration) {
|
|
71
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(expiration)) {
|
|
72
|
+
throw new Error("expiration must be a valid YYYY-MM-DD date.");
|
|
73
|
+
}
|
|
74
|
+
const parsed = new Date(`${expiration}T00:00:00.000Z`);
|
|
75
|
+
if (Number.isNaN(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== expiration) {
|
|
76
|
+
throw new Error("expiration must be a valid YYYY-MM-DD date.");
|
|
77
|
+
}
|
|
78
|
+
return Math.floor(parsed.getTime() / 1000);
|
|
79
|
+
}
|
|
67
80
|
function sortByVolume(contracts) {
|
|
68
81
|
return [...contracts].sort((a, b) => b.volume - a.volume);
|
|
69
82
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"option-chain.js","sourceRoot":"","sources":["../../../src/tools/options/option-chain.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"option-chain.js","sourceRoot":"","sources":["../../../src/tools/options/option-chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
2
|
+
declare const params: import("@sinclair/typebox").TObject<{
|
|
3
|
+
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"create_price_above">, import("@sinclair/typebox").TLiteral<"create_price_below">, import("@sinclair/typebox").TLiteral<"create_price_above_sma">, import("@sinclair/typebox").TLiteral<"create_price_below_sma">, import("@sinclair/typebox").TLiteral<"create_rsi_above">, import("@sinclair/typebox").TLiteral<"create_rsi_below">, import("@sinclair/typebox").TLiteral<"create_volume_spike">, import("@sinclair/typebox").TLiteral<"create_percent_move_up">, import("@sinclair/typebox").TLiteral<"create_percent_move_down">, import("@sinclair/typebox").TLiteral<"create_sma_cross_above">, import("@sinclair/typebox").TLiteral<"create_sma_cross_below">, import("@sinclair/typebox").TLiteral<"set_enabled">, import("@sinclair/typebox").TLiteral<"list">, import("@sinclair/typebox").TLiteral<"status">, import("@sinclair/typebox").TLiteral<"check">]>;
|
|
4
|
+
symbol: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
5
|
+
threshold: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
6
|
+
period: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
7
|
+
fast_period: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
8
|
+
slow_period: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
9
|
+
cooldown_seconds: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
10
|
+
id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
11
|
+
enabled: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
12
|
+
check_after_create: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
13
|
+
}>;
|
|
14
|
+
export declare const alertsTool: AgentTool<typeof params>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { ALERT_CONDITION_VERSION, percentMove, priceCrossesAbove, priceCrossesBelow, priceCrossesSma, rsiThreshold, smaCross, volumeSpike, } from "../../market-state/alert-conditions.js";
|
|
3
|
+
import { defaultAlertRunnerProviders, runAlertChecks } from "../../market-state/alert-runner.js";
|
|
4
|
+
import { deliverPendingNotifications } from "../../market-state/notification-delivery.js";
|
|
5
|
+
import { resolveInstrumentForMutation } from "../../market-state/resolve-for-mutation.js";
|
|
6
|
+
import { MarketStateService } from "../../market-state/service.js";
|
|
7
|
+
import { initDefaultDatabase } from "../../memory/sqlite.js";
|
|
8
|
+
const ACTION_DESCRIPTION = [
|
|
9
|
+
"One of: create_price_above, create_price_below, create_price_above_sma,",
|
|
10
|
+
"create_price_below_sma, create_rsi_above, create_rsi_below,",
|
|
11
|
+
"create_volume_spike, create_percent_move_up, create_percent_move_down,",
|
|
12
|
+
"create_sma_cross_above, create_sma_cross_below, set_enabled, list, status, check.",
|
|
13
|
+
"Use create_price_above/create_price_below for price alerts,",
|
|
14
|
+
"create_price_above_sma/create_price_below_sma for SMA crossing alerts,",
|
|
15
|
+
"create_percent_move_up/create_percent_move_down for one-day percent move alerts,",
|
|
16
|
+
"create_sma_cross_above/create_sma_cross_below for fast/slow SMA crossing alerts,",
|
|
17
|
+
"create_rsi_above/create_rsi_below for RSI alerts,",
|
|
18
|
+
"create_volume_spike for volume alerts, set_enabled to enable or disable an alert,",
|
|
19
|
+
"and status to inspect local runner/check history.",
|
|
20
|
+
"When the user asks to create an alert and check it now in the same request,",
|
|
21
|
+
"set check_after_create to true on the create action.",
|
|
22
|
+
].join(" ");
|
|
23
|
+
const params = Type.Object({
|
|
24
|
+
action: Type.Union([
|
|
25
|
+
Type.Literal("create_price_above"),
|
|
26
|
+
Type.Literal("create_price_below"),
|
|
27
|
+
Type.Literal("create_price_above_sma"),
|
|
28
|
+
Type.Literal("create_price_below_sma"),
|
|
29
|
+
Type.Literal("create_rsi_above"),
|
|
30
|
+
Type.Literal("create_rsi_below"),
|
|
31
|
+
Type.Literal("create_volume_spike"),
|
|
32
|
+
Type.Literal("create_percent_move_up"),
|
|
33
|
+
Type.Literal("create_percent_move_down"),
|
|
34
|
+
Type.Literal("create_sma_cross_above"),
|
|
35
|
+
Type.Literal("create_sma_cross_below"),
|
|
36
|
+
Type.Literal("set_enabled"),
|
|
37
|
+
Type.Literal("list"),
|
|
38
|
+
Type.Literal("status"),
|
|
39
|
+
Type.Literal("check"),
|
|
40
|
+
], { description: ACTION_DESCRIPTION }),
|
|
41
|
+
symbol: Type.Optional(Type.String({ description: "Ticker symbol for create actions" })),
|
|
42
|
+
threshold: Type.Optional(Type.Number({ description: "Price or indicator threshold for create actions" })),
|
|
43
|
+
period: Type.Optional(Type.Integer({
|
|
44
|
+
minimum: 1,
|
|
45
|
+
description: "Indicator lookback period for SMA/RSI alerts. Max: 200 for price-SMA, 100 for RSI/volume alerts",
|
|
46
|
+
})),
|
|
47
|
+
fast_period: Type.Optional(Type.Integer({
|
|
48
|
+
minimum: 1,
|
|
49
|
+
description: "Fast SMA lookback period for SMA-cross alerts. Default: 50",
|
|
50
|
+
})),
|
|
51
|
+
slow_period: Type.Optional(Type.Integer({
|
|
52
|
+
minimum: 1,
|
|
53
|
+
maximum: 400,
|
|
54
|
+
description: "Slow SMA lookback period for SMA-cross alerts. Default: 200, max: 400",
|
|
55
|
+
})),
|
|
56
|
+
cooldown_seconds: Type.Optional(Type.Integer({
|
|
57
|
+
minimum: 0,
|
|
58
|
+
description: "Cooldown between repeated trigger events. Default: 3600",
|
|
59
|
+
})),
|
|
60
|
+
id: Type.Optional(Type.Number({ description: "Alert rule id for update actions" })),
|
|
61
|
+
enabled: Type.Optional(Type.Boolean({ description: "Whether an alert rule is enabled" })),
|
|
62
|
+
check_after_create: Type.Optional(Type.Boolean({
|
|
63
|
+
description: "Set true only when the user asks to check/run alerts immediately after creating this alert in the same request.",
|
|
64
|
+
})),
|
|
65
|
+
});
|
|
66
|
+
export const alertsTool = {
|
|
67
|
+
name: "manage_alerts",
|
|
68
|
+
label: "Alerts",
|
|
69
|
+
description: "Create, pause/resume, list, check, and inspect status for durable local alerts. Actions include create_price_above, create_price_below, create_price_above_sma, create_price_below_sma, create_rsi_above, create_rsi_below, create_volume_spike, create_percent_move_up, create_percent_move_down, create_sma_cross_above, create_sma_cross_below, set_enabled, list, status, and check. Local background monitoring runs only while an OpenCandle writer/monitor process is active; manual checks are always available. If the user asks to create an alert and check it now, use the create action with check_after_create=true.",
|
|
70
|
+
parameters: params,
|
|
71
|
+
async execute(_toolCallId, args) {
|
|
72
|
+
const db = initDefaultDatabase();
|
|
73
|
+
const service = new MarketStateService(db);
|
|
74
|
+
try {
|
|
75
|
+
const cooldownSeconds = validateCooldownSeconds(args.cooldown_seconds);
|
|
76
|
+
if (args.action === "create_price_above" || args.action === "create_price_below") {
|
|
77
|
+
if (!args.symbol || args.threshold == null) {
|
|
78
|
+
throw new Error("symbol and threshold are required for create alert actions.");
|
|
79
|
+
}
|
|
80
|
+
const resolution = await resolveInstrumentForMutation(args.symbol);
|
|
81
|
+
if (resolution.status === "needs_selection")
|
|
82
|
+
return candidateResult(resolution, "alert");
|
|
83
|
+
const instrument = service.upsertInstrumentRecord(resolution.instrument);
|
|
84
|
+
const isAbove = args.action === "create_price_above";
|
|
85
|
+
const rule = service.createAlertRule({
|
|
86
|
+
scopeType: "instrument",
|
|
87
|
+
instrumentId: instrument.id,
|
|
88
|
+
conditionType: isAbove ? "price_crosses_above" : "price_crosses_below",
|
|
89
|
+
conditionVersion: ALERT_CONDITION_VERSION,
|
|
90
|
+
condition: isAbove
|
|
91
|
+
? priceCrossesAbove(args.threshold)
|
|
92
|
+
: priceCrossesBelow(args.threshold),
|
|
93
|
+
timeframe: "quote",
|
|
94
|
+
cooldownSeconds,
|
|
95
|
+
});
|
|
96
|
+
return await createResultMaybeChecked(service, rule, `Created local alert ${rule.conditionType} for ${instrument.symbol} at $${args.threshold}.`, args.check_after_create);
|
|
97
|
+
}
|
|
98
|
+
if (args.action === "create_price_above_sma" || args.action === "create_price_below_sma") {
|
|
99
|
+
if (!args.symbol) {
|
|
100
|
+
throw new Error("symbol is required for SMA alert actions.");
|
|
101
|
+
}
|
|
102
|
+
// Runner evaluates price_crosses_sma against 1y of daily bars (~252).
|
|
103
|
+
const period = validateLookbackPeriod(args.period ?? 50, 200);
|
|
104
|
+
const resolution = await resolveInstrumentForMutation(args.symbol);
|
|
105
|
+
if (resolution.status === "needs_selection")
|
|
106
|
+
return candidateResult(resolution, "alert");
|
|
107
|
+
const instrument = service.upsertInstrumentRecord(resolution.instrument);
|
|
108
|
+
const direction = args.action === "create_price_above_sma" ? "above" : "below";
|
|
109
|
+
const rule = service.createAlertRule({
|
|
110
|
+
scopeType: "instrument",
|
|
111
|
+
instrumentId: instrument.id,
|
|
112
|
+
conditionType: "price_crosses_sma",
|
|
113
|
+
conditionVersion: ALERT_CONDITION_VERSION,
|
|
114
|
+
condition: priceCrossesSma(period, direction),
|
|
115
|
+
timeframe: "1d",
|
|
116
|
+
cooldownSeconds,
|
|
117
|
+
});
|
|
118
|
+
return await createResultMaybeChecked(service, rule, `Created local alert price_crosses_sma for ${instrument.symbol} using SMA(${period}).`, args.check_after_create);
|
|
119
|
+
}
|
|
120
|
+
if (args.action === "create_rsi_above" || args.action === "create_rsi_below") {
|
|
121
|
+
if (!args.symbol || args.threshold == null) {
|
|
122
|
+
throw new Error("symbol and threshold are required for RSI alert actions.");
|
|
123
|
+
}
|
|
124
|
+
// Runner evaluates rsi_threshold against 6mo of daily bars (~126).
|
|
125
|
+
const period = validateLookbackPeriod(args.period ?? 14, 100);
|
|
126
|
+
const resolution = await resolveInstrumentForMutation(args.symbol);
|
|
127
|
+
if (resolution.status === "needs_selection")
|
|
128
|
+
return candidateResult(resolution, "alert");
|
|
129
|
+
const instrument = service.upsertInstrumentRecord(resolution.instrument);
|
|
130
|
+
const direction = args.action === "create_rsi_above" ? "above" : "below";
|
|
131
|
+
const rule = service.createAlertRule({
|
|
132
|
+
scopeType: "instrument",
|
|
133
|
+
instrumentId: instrument.id,
|
|
134
|
+
conditionType: "rsi_threshold",
|
|
135
|
+
conditionVersion: ALERT_CONDITION_VERSION,
|
|
136
|
+
condition: rsiThreshold(period, args.threshold, direction),
|
|
137
|
+
timeframe: "1d",
|
|
138
|
+
cooldownSeconds,
|
|
139
|
+
});
|
|
140
|
+
return await createResultMaybeChecked(service, rule, `Created local alert rsi_threshold for ${instrument.symbol}: RSI(${period}) ${direction} ${args.threshold}.`, args.check_after_create);
|
|
141
|
+
}
|
|
142
|
+
if (args.action === "create_volume_spike") {
|
|
143
|
+
if (!args.symbol) {
|
|
144
|
+
throw new Error("symbol is required for volume-spike alert actions.");
|
|
145
|
+
}
|
|
146
|
+
// Runner evaluates volume_spike against 6mo of daily bars (~126).
|
|
147
|
+
const period = validateLookbackPeriod(args.period ?? 20, 100);
|
|
148
|
+
const multiplier = args.threshold ?? 2;
|
|
149
|
+
const resolution = await resolveInstrumentForMutation(args.symbol);
|
|
150
|
+
if (resolution.status === "needs_selection")
|
|
151
|
+
return candidateResult(resolution, "alert");
|
|
152
|
+
const instrument = service.upsertInstrumentRecord(resolution.instrument);
|
|
153
|
+
const rule = service.createAlertRule({
|
|
154
|
+
scopeType: "instrument",
|
|
155
|
+
instrumentId: instrument.id,
|
|
156
|
+
conditionType: "volume_spike",
|
|
157
|
+
conditionVersion: ALERT_CONDITION_VERSION,
|
|
158
|
+
condition: volumeSpike(period, multiplier),
|
|
159
|
+
timeframe: "1d",
|
|
160
|
+
cooldownSeconds,
|
|
161
|
+
});
|
|
162
|
+
return await createResultMaybeChecked(service, rule, `Created local alert volume_spike for ${instrument.symbol}: volume > ${multiplier}x ${period}-bar average.`, args.check_after_create);
|
|
163
|
+
}
|
|
164
|
+
if (args.action === "create_percent_move_up" || args.action === "create_percent_move_down") {
|
|
165
|
+
if (!args.symbol || args.threshold == null) {
|
|
166
|
+
throw new Error("symbol and threshold are required for percent-move alert actions.");
|
|
167
|
+
}
|
|
168
|
+
if (args.threshold <= 0) {
|
|
169
|
+
throw new Error("threshold must be greater than 0 for percent-move alert actions.");
|
|
170
|
+
}
|
|
171
|
+
const resolution = await resolveInstrumentForMutation(args.symbol);
|
|
172
|
+
if (resolution.status === "needs_selection")
|
|
173
|
+
return candidateResult(resolution, "alert");
|
|
174
|
+
const instrument = service.upsertInstrumentRecord(resolution.instrument);
|
|
175
|
+
const direction = args.action === "create_percent_move_up" ? "up" : "down";
|
|
176
|
+
const rule = service.createAlertRule({
|
|
177
|
+
scopeType: "instrument",
|
|
178
|
+
instrumentId: instrument.id,
|
|
179
|
+
conditionType: "percent_move",
|
|
180
|
+
conditionVersion: ALERT_CONDITION_VERSION,
|
|
181
|
+
condition: percentMove(direction, args.threshold),
|
|
182
|
+
timeframe: "1d",
|
|
183
|
+
cooldownSeconds,
|
|
184
|
+
});
|
|
185
|
+
return await createResultMaybeChecked(service, rule, `Created local alert percent_move for ${instrument.symbol}: ${direction} ${args.threshold}%.`, args.check_after_create);
|
|
186
|
+
}
|
|
187
|
+
if (args.action === "create_sma_cross_above" || args.action === "create_sma_cross_below") {
|
|
188
|
+
if (!args.symbol) {
|
|
189
|
+
throw new Error("symbol is required for SMA-cross alert actions.");
|
|
190
|
+
}
|
|
191
|
+
const fastPeriod = args.fast_period ?? 50;
|
|
192
|
+
const slowPeriod = args.slow_period ?? 200;
|
|
193
|
+
if (!Number.isInteger(fastPeriod) || !Number.isInteger(slowPeriod)) {
|
|
194
|
+
throw new Error("fast_period and slow_period must be whole-number lookback periods for SMA-cross alert actions.");
|
|
195
|
+
}
|
|
196
|
+
if (fastPeriod <= 0 || slowPeriod <= 0) {
|
|
197
|
+
throw new Error("fast_period and slow_period must be greater than 0 for SMA-cross alert actions.");
|
|
198
|
+
}
|
|
199
|
+
if (fastPeriod >= slowPeriod) {
|
|
200
|
+
throw new Error("fast_period must be less than slow_period for SMA-cross alert actions.");
|
|
201
|
+
}
|
|
202
|
+
// Runner evaluates sma_cross against 2y of daily bars (~504).
|
|
203
|
+
if (slowPeriod > 400) {
|
|
204
|
+
throw new Error("slow_period must be at most 400 so alert checks can evaluate it against the runner's 2y daily history window.");
|
|
205
|
+
}
|
|
206
|
+
const resolution = await resolveInstrumentForMutation(args.symbol);
|
|
207
|
+
if (resolution.status === "needs_selection")
|
|
208
|
+
return candidateResult(resolution, "alert");
|
|
209
|
+
const instrument = service.upsertInstrumentRecord(resolution.instrument);
|
|
210
|
+
const direction = args.action === "create_sma_cross_above" ? "above" : "below";
|
|
211
|
+
const rule = service.createAlertRule({
|
|
212
|
+
scopeType: "instrument",
|
|
213
|
+
instrumentId: instrument.id,
|
|
214
|
+
conditionType: "sma_cross",
|
|
215
|
+
conditionVersion: ALERT_CONDITION_VERSION,
|
|
216
|
+
condition: smaCross(fastPeriod, slowPeriod, direction),
|
|
217
|
+
timeframe: "1d",
|
|
218
|
+
cooldownSeconds,
|
|
219
|
+
});
|
|
220
|
+
return await createResultMaybeChecked(service, rule, `Created local alert sma_cross for ${instrument.symbol}: SMA(${fastPeriod}) crosses ${direction} SMA(${slowPeriod}).`, args.check_after_create);
|
|
221
|
+
}
|
|
222
|
+
if (args.action === "list") {
|
|
223
|
+
const rules = service.listAlertRules();
|
|
224
|
+
if (rules.length === 0) {
|
|
225
|
+
return { content: [{ type: "text", text: "No alert rules created yet." }], details: [] };
|
|
226
|
+
}
|
|
227
|
+
const lines = ["**Alerts** — local runner eligible; manual checks available", ""];
|
|
228
|
+
for (const rule of rules) {
|
|
229
|
+
const instrument = rule.instrumentId == null ? null : service.getInstrument(rule.instrumentId);
|
|
230
|
+
lines.push(` #${rule.id} ${instrument?.symbol ?? "watchlist"} ${rule.conditionType} (${rule.enabled ? "enabled" : "disabled"})`);
|
|
231
|
+
}
|
|
232
|
+
return { content: [{ type: "text", text: lines.join("\n") }], details: rules };
|
|
233
|
+
}
|
|
234
|
+
if (args.action === "status") {
|
|
235
|
+
const runnerLease = service.getAutomationRunnerLease();
|
|
236
|
+
const recentCheckRuns = service.listAlertCheckRuns().slice(0, 10);
|
|
237
|
+
const stateLine = runnerLease
|
|
238
|
+
? `Running locally — ${runnerLease.ownerKind} ${runnerLease.ownerId}; heartbeat ${runnerLease.heartbeatAt}; expires ${runnerLease.expiresAt}.`
|
|
239
|
+
: "Manual only — no active local runner lease. Keep the GUI/TUI writer or `opencandle monitor` open for background checks.";
|
|
240
|
+
const lines = ["**Alert Automation Status**", "", stateLine];
|
|
241
|
+
if (recentCheckRuns.length === 0) {
|
|
242
|
+
lines.push("", "No alert check runs yet.");
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
lines.push("", "Recent checks:");
|
|
246
|
+
for (const run of recentCheckRuns) {
|
|
247
|
+
lines.push(` #${run.id} ${run.triggerType} ${run.status} checked=${run.checkedCount} triggered=${run.triggeredCount} unavailable=${run.unavailableCount}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
252
|
+
details: { runnerLease, recentCheckRuns },
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
if (args.action === "set_enabled") {
|
|
256
|
+
if (args.id == null || args.enabled == null) {
|
|
257
|
+
throw new Error("id and enabled are required for set_enabled.");
|
|
258
|
+
}
|
|
259
|
+
const rule = service.setAlertRuleEnabled(args.id, args.enabled);
|
|
260
|
+
if (rule == null) {
|
|
261
|
+
return {
|
|
262
|
+
content: [
|
|
263
|
+
{
|
|
264
|
+
type: "text",
|
|
265
|
+
text: `Alert #${args.id} not found. Use the list action to see alert ids.`,
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
details: null,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
content: [
|
|
273
|
+
{
|
|
274
|
+
type: "text",
|
|
275
|
+
text: `${rule.enabled ? "Enabled" : "Disabled"} alert #${rule.id}.`,
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
details: rule,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const result = await checkAlerts(service);
|
|
282
|
+
return {
|
|
283
|
+
content: [{ type: "text", text: result.lines.join("\n") }],
|
|
284
|
+
details: result,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
finally {
|
|
288
|
+
db.close();
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
function validateLookbackPeriod(period, maxPeriod) {
|
|
293
|
+
if (!Number.isInteger(period) || period <= 0) {
|
|
294
|
+
throw new Error("period must be a whole-number lookback period greater than 0 for indicator alert actions.");
|
|
295
|
+
}
|
|
296
|
+
if (period > maxPeriod) {
|
|
297
|
+
throw new Error(`period must be at most ${maxPeriod} so alert checks can evaluate it against the runner's daily history window.`);
|
|
298
|
+
}
|
|
299
|
+
return period;
|
|
300
|
+
}
|
|
301
|
+
function validateCooldownSeconds(cooldownSeconds) {
|
|
302
|
+
const resolved = cooldownSeconds ?? 3600;
|
|
303
|
+
if (!Number.isInteger(resolved) || resolved < 0) {
|
|
304
|
+
throw new Error("cooldown_seconds must be a whole number greater than or equal to 0.");
|
|
305
|
+
}
|
|
306
|
+
return resolved;
|
|
307
|
+
}
|
|
308
|
+
async function checkAlerts(service) {
|
|
309
|
+
const enabled = service
|
|
310
|
+
.listAlertRules()
|
|
311
|
+
.filter((rule) => rule.enabled && rule.status === "active");
|
|
312
|
+
if (enabled.length === 0)
|
|
313
|
+
return { checked: 0, triggered: 0, lines: ["No enabled alert rules to check."] };
|
|
314
|
+
const result = await runAlertChecks(service, {
|
|
315
|
+
ownerId: "manual-tool",
|
|
316
|
+
triggerType: "manual",
|
|
317
|
+
providers: defaultAlertRunnerProviders,
|
|
318
|
+
});
|
|
319
|
+
await deliverPendingNotifications(service);
|
|
320
|
+
return {
|
|
321
|
+
checked: result.checked,
|
|
322
|
+
triggered: result.triggered,
|
|
323
|
+
lines: [
|
|
324
|
+
`**Manual Alert Check** — ${enabled.length} rule(s)`,
|
|
325
|
+
"",
|
|
326
|
+
...result.lines.map((line) => ` ${line}`),
|
|
327
|
+
],
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
function candidateResult(resolution, target) {
|
|
331
|
+
return {
|
|
332
|
+
content: [
|
|
333
|
+
{
|
|
334
|
+
type: "text",
|
|
335
|
+
text: `Could not verify ${resolution.query}. Choose one of the returned candidates before creating the ${target}.`,
|
|
336
|
+
},
|
|
337
|
+
],
|
|
338
|
+
details: resolution,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async function createResultMaybeChecked(service, rule, createdText, checkAfterCreate) {
|
|
342
|
+
if (!checkAfterCreate) {
|
|
343
|
+
return {
|
|
344
|
+
content: [{ type: "text", text: createdText }],
|
|
345
|
+
details: rule,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const check = await checkAlerts(service);
|
|
349
|
+
return {
|
|
350
|
+
content: [{ type: "text", text: `${createdText}\n\n${check.lines.join("\n")}` }],
|
|
351
|
+
details: {
|
|
352
|
+
created: rule,
|
|
353
|
+
check,
|
|
354
|
+
},
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=alerts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alerts.js","sourceRoot":"","sources":["../../../src/tools/portfolio/alerts.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ export declare function computeCorrelation(returnsA: number[], returnsB: number[
|
|
|
4
4
|
export declare function alignReturnsByDate(historiesBySymbol: Map<string, OHLCV[]>, minOverlap?: number): Map<string, number[]>;
|
|
5
5
|
declare const params: import("@sinclair/typebox").TObject<{
|
|
6
6
|
symbols: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
7
|
-
period: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").
|
|
7
|
+
period: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"6mo" | "1y" | "2y">[]>>;
|
|
8
8
|
}>;
|
|
9
9
|
export declare const correlationTool: AgentTool<typeof params>;
|
|
10
10
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
-
import { getHistory } from "../../providers/yahoo-finance.js";
|
|
3
2
|
import { wrapProvider } from "../../providers/wrap-provider.js";
|
|
3
|
+
import { getHistory } from "../../providers/yahoo-finance.js";
|
|
4
4
|
import { computeDailyReturns } from "./risk-analysis.js";
|
|
5
5
|
export function computeCorrelation(returnsA, returnsB) {
|
|
6
6
|
const n = Math.min(returnsA.length, returnsB.length);
|
|
@@ -26,6 +26,7 @@ export function computeCorrelation(returnsA, returnsB) {
|
|
|
26
26
|
return cov / Math.sqrt(varA * varB);
|
|
27
27
|
}
|
|
28
28
|
const DEFAULT_MIN_OVERLAP = 20;
|
|
29
|
+
const CORRELATION_PERIODS = ["6mo", "1y", "2y"];
|
|
29
30
|
export function alignReturnsByDate(historiesBySymbol, minOverlap = DEFAULT_MIN_OVERLAP) {
|
|
30
31
|
// Build date → close price maps for each symbol
|
|
31
32
|
const priceByDate = new Map();
|
|
@@ -39,7 +40,9 @@ export function alignReturnsByDate(historiesBySymbol, minOverlap = DEFAULT_MIN_O
|
|
|
39
40
|
// Find common dates across all symbols
|
|
40
41
|
const symbols = [...historiesBySymbol.keys()];
|
|
41
42
|
const firstDates = priceByDate.get(symbols[0]);
|
|
42
|
-
const commonDates = [...firstDates.keys()]
|
|
43
|
+
const commonDates = [...firstDates.keys()]
|
|
44
|
+
.filter((date) => symbols.every((s) => priceByDate.get(s).has(date)))
|
|
45
|
+
.sort();
|
|
43
46
|
if (commonDates.length < minOverlap) {
|
|
44
47
|
throw new Error(`Insufficient date overlap for correlation: ${commonDates.length} common dates (need ${minOverlap}+). Symbols may trade on different exchanges or have sparse history.`);
|
|
45
48
|
}
|
|
@@ -57,12 +60,14 @@ const params = Type.Object({
|
|
|
57
60
|
description: "Array of 2+ ticker symbols to compute correlation matrix (e.g. ['AAPL','MSFT','GOOGL'])",
|
|
58
61
|
minItems: 2,
|
|
59
62
|
}),
|
|
60
|
-
period: Type.Optional(Type.
|
|
63
|
+
period: Type.Optional(Type.Union(CORRELATION_PERIODS.map((period) => Type.Literal(period)), {
|
|
64
|
+
description: "Historical period: 6mo, 1y, 2y. Default: 1y",
|
|
65
|
+
})),
|
|
61
66
|
});
|
|
62
67
|
export const correlationTool = {
|
|
63
68
|
name: "analyze_correlation",
|
|
64
69
|
label: "Correlation Matrix",
|
|
65
|
-
description: "Compute pairwise return correlations between 2+ stocks. Identifies highly correlated positions (|r| > 0.7) as concentration risk. Useful for portfolio diversification analysis.",
|
|
70
|
+
description: "Compute pairwise return correlations between 2+ stocks. If one symbol cannot be fetched, computes over the remaining 2+ symbols and lists dropped symbols. Identifies highly correlated positions (|r| > 0.7) as concentration risk. Useful for portfolio diversification analysis.",
|
|
66
71
|
parameters: params,
|
|
67
72
|
async execute(_toolCallId, args) {
|
|
68
73
|
const symbols = args.symbols.map((s) => s.toUpperCase());
|
|
@@ -75,10 +80,19 @@ export const correlationTool = {
|
|
|
75
80
|
symbol: s,
|
|
76
81
|
result: await wrapProvider("yahoo", () => getHistory(s, period, "1d")),
|
|
77
82
|
})));
|
|
78
|
-
const
|
|
79
|
-
|
|
83
|
+
const dropped = results.flatMap((r) => r.result.status === "unavailable" ? [{ symbol: r.symbol, reason: r.result.reason }] : []);
|
|
84
|
+
const succeeded = results.filter((r) => r.result.status === "ok");
|
|
85
|
+
if (succeeded.length < 2) {
|
|
86
|
+
const droppedText = dropped.length > 0
|
|
87
|
+
? `\n\nSymbols dropped:\n${dropped.map((d) => ` - ${d.symbol}: ${d.reason}`).join("\n")}`
|
|
88
|
+
: "";
|
|
80
89
|
return {
|
|
81
|
-
content: [
|
|
90
|
+
content: [
|
|
91
|
+
{
|
|
92
|
+
type: "text",
|
|
93
|
+
text: `⚠ Correlation analysis unavailable — need at least 2 symbols with usable history.${droppedText}`,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
82
96
|
details: null,
|
|
83
97
|
};
|
|
84
98
|
}
|
|
@@ -88,12 +102,13 @@ export const correlationTool = {
|
|
|
88
102
|
historiesBySymbol.set(sym, r.data);
|
|
89
103
|
}
|
|
90
104
|
const returnsBySymbol = alignReturnsByDate(historiesBySymbol);
|
|
105
|
+
const survivorSymbols = [...historiesBySymbol.keys()];
|
|
91
106
|
// Build correlation matrix
|
|
92
107
|
const matrix = {};
|
|
93
108
|
const warnings = [];
|
|
94
|
-
for (const a of
|
|
109
|
+
for (const a of survivorSymbols) {
|
|
95
110
|
matrix[a] = {};
|
|
96
|
-
for (const b of
|
|
111
|
+
for (const b of survivorSymbols) {
|
|
97
112
|
if (a === b) {
|
|
98
113
|
matrix[a][b] = 1.0;
|
|
99
114
|
}
|
|
@@ -111,12 +126,17 @@ export const correlationTool = {
|
|
|
111
126
|
}
|
|
112
127
|
// Format output
|
|
113
128
|
const header = `**Correlation Matrix** (${period} daily returns)`;
|
|
114
|
-
const colHeader = `${"".padEnd(8)} ${
|
|
115
|
-
const rows =
|
|
116
|
-
const cells =
|
|
129
|
+
const colHeader = `${"".padEnd(8)} ${survivorSymbols.map((s) => s.padStart(8)).join("")}`;
|
|
130
|
+
const rows = survivorSymbols.map((a) => {
|
|
131
|
+
const cells = survivorSymbols.map((b) => matrix[a][b].toFixed(2).padStart(8));
|
|
117
132
|
return `${a.padEnd(8)} ${cells.join("")}`;
|
|
118
133
|
});
|
|
119
134
|
const lines = [header, "", colHeader, ...rows];
|
|
135
|
+
if (dropped.length > 0) {
|
|
136
|
+
lines.push("", "Symbols dropped:");
|
|
137
|
+
for (const drop of dropped)
|
|
138
|
+
lines.push(` - ${drop.symbol}: ${drop.reason}`);
|
|
139
|
+
}
|
|
120
140
|
if (warnings.length > 0) {
|
|
121
141
|
lines.push("", "**Concentration Warnings:**");
|
|
122
142
|
for (const w of warnings)
|
|
@@ -127,7 +147,7 @@ export const correlationTool = {
|
|
|
127
147
|
}
|
|
128
148
|
return {
|
|
129
149
|
content: [{ type: "text", text: lines.join("\n") }],
|
|
130
|
-
details: { matrix, warnings },
|
|
150
|
+
details: { matrix, warnings, dropped },
|
|
131
151
|
};
|
|
132
152
|
},
|
|
133
153
|
};
|