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,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { httpGet, HttpError } from "../infra/http-client.js";
|
|
3
|
-
import { cache, TTL, STALE_LIMIT } from "../infra/cache.js";
|
|
4
|
-
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
1
|
+
import { SafeSearchType, SearchTimeType, search, searchNews } from "duck-duck-scrape";
|
|
5
2
|
import { getConfig } from "../config.js";
|
|
6
|
-
import {
|
|
3
|
+
import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
|
|
4
|
+
import { HttpError, httpGet } from "../infra/http-client.js";
|
|
5
|
+
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
7
6
|
import { exaSearch } from "./exa-search.js";
|
|
8
7
|
import { ProviderCredentialError } from "./provider-credential-error.js";
|
|
8
|
+
import { withFallback } from "./with-fallback.js";
|
|
9
9
|
const BARE_TICKER = /^[A-Z]{1,5}$/;
|
|
10
10
|
const CASHTAG = /^\$[A-Z]{1,5}$/;
|
|
11
11
|
/**
|
|
@@ -107,10 +107,14 @@ export async function ddgSearch(query, opts) {
|
|
|
107
107
|
const BRAVE_BASE = "https://api.search.brave.com/res/v1";
|
|
108
108
|
function mapBraveFreshness(freshness) {
|
|
109
109
|
switch (freshness) {
|
|
110
|
-
case "hours":
|
|
111
|
-
|
|
112
|
-
case "
|
|
113
|
-
|
|
110
|
+
case "hours":
|
|
111
|
+
return "ph";
|
|
112
|
+
case "day":
|
|
113
|
+
return "pd";
|
|
114
|
+
case "week":
|
|
115
|
+
return "pw";
|
|
116
|
+
case "month":
|
|
117
|
+
return "pm";
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
function mapBraveNewsResult(r) {
|
|
@@ -203,9 +207,16 @@ export async function searchWeb(query, opts) {
|
|
|
203
207
|
break;
|
|
204
208
|
case "brave":
|
|
205
209
|
if (!config.braveApiKey) {
|
|
206
|
-
return {
|
|
210
|
+
return {
|
|
211
|
+
status: "unavailable",
|
|
212
|
+
reason: "BRAVE_API_KEY not configured",
|
|
213
|
+
provider: "brave_search",
|
|
214
|
+
};
|
|
207
215
|
}
|
|
208
|
-
entries.push({
|
|
216
|
+
entries.push({
|
|
217
|
+
provider: "brave_search",
|
|
218
|
+
fn: () => braveSearch(normalized, resolved, config.braveApiKey),
|
|
219
|
+
});
|
|
209
220
|
break;
|
|
210
221
|
case "ddg":
|
|
211
222
|
entries.push({ provider: "ddg", fn: () => ddgSearch(normalized, resolved) });
|
|
@@ -216,7 +227,10 @@ export async function searchWeb(query, opts) {
|
|
|
216
227
|
// Default cascade: Exa → Brave → DDG
|
|
217
228
|
entries.push({ provider: "exa", fn: () => exaSearch(normalized, resolved) });
|
|
218
229
|
if (config.braveApiKey) {
|
|
219
|
-
entries.push({
|
|
230
|
+
entries.push({
|
|
231
|
+
provider: "brave_search",
|
|
232
|
+
fn: () => braveSearch(normalized, resolved, config.braveApiKey),
|
|
233
|
+
});
|
|
220
234
|
}
|
|
221
235
|
entries.push({ provider: "ddg", fn: () => ddgSearch(normalized, resolved) });
|
|
222
236
|
return withFallback(entries);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../src/providers/web-search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../src/providers/web-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { wrapProvider } from "./wrap-provider.js";
|
|
2
1
|
import { getProviderTracker } from "../runtime/run-context.js";
|
|
2
|
+
import { wrapProvider } from "./wrap-provider.js";
|
|
3
3
|
/**
|
|
4
4
|
* Try providers in order, stopping at the first success.
|
|
5
5
|
* Skips circuit-open providers. Each provider call goes through wrapProvider
|
|
@@ -12,6 +12,7 @@ import { getProviderTracker } from "../runtime/run-context.js";
|
|
|
12
12
|
export async function withFallback(entries) {
|
|
13
13
|
const tracker = getProviderTracker();
|
|
14
14
|
const attempted = [];
|
|
15
|
+
const failures = [];
|
|
15
16
|
for (const entry of entries) {
|
|
16
17
|
if (tracker?.isCircuitOpen(entry.provider))
|
|
17
18
|
continue;
|
|
@@ -19,12 +20,13 @@ export async function withFallback(entries) {
|
|
|
19
20
|
const result = await wrapProvider(entry.provider, entry.fn);
|
|
20
21
|
if (result.status === "ok")
|
|
21
22
|
return result;
|
|
23
|
+
failures.push(`${entry.provider}: ${result.reason}`);
|
|
22
24
|
// wrapProvider already called recordFailure on the tracker
|
|
23
25
|
}
|
|
24
26
|
return {
|
|
25
27
|
status: "unavailable",
|
|
26
28
|
reason: attempted.length > 0
|
|
27
|
-
? `all providers failed: ${
|
|
29
|
+
? `all providers failed: ${failures.join("; ")}`
|
|
28
30
|
: `all providers circuit-open: ${entries.map((e) => e.provider).join(", ")}`,
|
|
29
31
|
provider: entries[0]?.provider ?? "unknown",
|
|
30
32
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"with-fallback.js","sourceRoot":"","sources":["../../src/providers/with-fallback.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"with-fallback.js","sourceRoot":"","sources":["../../src/providers/with-fallback.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOlD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,OAA2B;IAC/D,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IACrC,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC;YAAE,SAAS;QACrD,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAE/B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5D,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC;QAC1C,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACrD,2DAA2D;IAC7D,CAAC;IAED,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,MAAM,EACJ,SAAS,CAAC,MAAM,GAAG,CAAC;YAClB,CAAC,CAAC,yBAAyB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAChD,CAAC,CAAC,+BAA+B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAChF,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,SAAS;KAC5C,CAAC;AACJ,CAAC"}
|
|
@@ -13,8 +13,7 @@ import type { ProviderResult } from "../runtime/evidence.js";
|
|
|
13
13
|
* When a run context is active, checks circuit breaker state before
|
|
14
14
|
* calling and records failures after.
|
|
15
15
|
*
|
|
16
|
-
* After a successful provider call,
|
|
17
|
-
*
|
|
18
|
-
* and propagates that metadata on the result.
|
|
16
|
+
* After a successful provider call, propagates stale cache metadata recorded
|
|
17
|
+
* in the current provider call's async scope.
|
|
19
18
|
*/
|
|
20
19
|
export declare function wrapProvider<T>(providerId: string, fn: () => Promise<T>): Promise<ProviderResult<T>>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { runWithStaleMetadata } from "../infra/cache.js";
|
|
1
2
|
import { getProviderTracker } from "../runtime/run-context.js";
|
|
2
|
-
import {
|
|
3
|
+
import { InvalidSymbolError } from "./errors.js";
|
|
4
|
+
import { ExternalToolError, ExternalToolNotInstalled } from "./external-tool-error.js";
|
|
3
5
|
import { ProviderCredentialError } from "./provider-credential-error.js";
|
|
4
6
|
/**
|
|
5
7
|
* Wrap a provider function call so that thrown exceptions are caught
|
|
@@ -15,9 +17,8 @@ import { ProviderCredentialError } from "./provider-credential-error.js";
|
|
|
15
17
|
* When a run context is active, checks circuit breaker state before
|
|
16
18
|
* calling and records failures after.
|
|
17
19
|
*
|
|
18
|
-
* After a successful provider call,
|
|
19
|
-
*
|
|
20
|
-
* and propagates that metadata on the result.
|
|
20
|
+
* After a successful provider call, propagates stale cache metadata recorded
|
|
21
|
+
* in the current provider call's async scope.
|
|
21
22
|
*/
|
|
22
23
|
export async function wrapProvider(providerId, fn) {
|
|
23
24
|
const tracker = getProviderTracker();
|
|
@@ -29,13 +30,12 @@ export async function wrapProvider(providerId, fn) {
|
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
try {
|
|
32
|
-
const data = await fn
|
|
33
|
-
const { stale, cachedAt } = cache.consumeStaleFlag();
|
|
33
|
+
const { value: data, stale } = await runWithStaleMetadata(fn);
|
|
34
34
|
return {
|
|
35
35
|
status: "ok",
|
|
36
36
|
data,
|
|
37
|
-
timestamp: stale ? new Date(cachedAt).toISOString() : new Date().toISOString(),
|
|
38
|
-
stale: stale
|
|
37
|
+
timestamp: stale ? new Date(stale.cachedAt).toISOString() : new Date().toISOString(),
|
|
38
|
+
stale: stale ? true : undefined,
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
catch (error) {
|
|
@@ -46,6 +46,20 @@ export async function wrapProvider(providerId, fn) {
|
|
|
46
46
|
if (error instanceof ProviderCredentialError) {
|
|
47
47
|
throw error;
|
|
48
48
|
}
|
|
49
|
+
if (isExternalToolSetupError(error)) {
|
|
50
|
+
return {
|
|
51
|
+
status: "unavailable",
|
|
52
|
+
reason: error.message,
|
|
53
|
+
provider: providerId,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (error instanceof InvalidSymbolError) {
|
|
57
|
+
return {
|
|
58
|
+
status: "unavailable",
|
|
59
|
+
reason: error.message,
|
|
60
|
+
provider: providerId,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
49
63
|
tracker?.recordFailure(providerId);
|
|
50
64
|
const reason = error instanceof Error ? error.message : "unknown_error";
|
|
51
65
|
return {
|
|
@@ -55,4 +69,26 @@ export async function wrapProvider(providerId, fn) {
|
|
|
55
69
|
};
|
|
56
70
|
}
|
|
57
71
|
}
|
|
72
|
+
function isExternalToolSetupError(error) {
|
|
73
|
+
if (error instanceof ExternalToolNotInstalled)
|
|
74
|
+
return true;
|
|
75
|
+
if (!(error instanceof ExternalToolError))
|
|
76
|
+
return false;
|
|
77
|
+
const code = error.code?.toLowerCase() ?? "";
|
|
78
|
+
const message = error.message.toLowerCase();
|
|
79
|
+
return (code.includes("auth") ||
|
|
80
|
+
code.includes("session") ||
|
|
81
|
+
code.includes("unauthorized") ||
|
|
82
|
+
code.includes("expired") ||
|
|
83
|
+
message.includes("no twitter cookies") ||
|
|
84
|
+
message.includes("no twitter session") ||
|
|
85
|
+
message.includes("no reddit cookies") ||
|
|
86
|
+
message.includes("session missing") ||
|
|
87
|
+
message.includes("not authenticated") ||
|
|
88
|
+
message.includes("no cookies") ||
|
|
89
|
+
message.includes("rdt login") ||
|
|
90
|
+
message.includes("401") ||
|
|
91
|
+
message.includes("unauthorized") ||
|
|
92
|
+
message.includes("expired"));
|
|
93
|
+
}
|
|
58
94
|
//# sourceMappingURL=wrap-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrap-provider.js","sourceRoot":"","sources":["../../src/providers/wrap-provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wrap-provider.js","sourceRoot":"","sources":["../../src/providers/wrap-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { OHLCV, StockQuote } from "../types/market.js";
|
|
2
2
|
import type { OptionsChain } from "../types/options.js";
|
|
3
3
|
import type { FundHoldings } from "../types/portfolio.js";
|
|
4
4
|
export declare function getQuote(symbol: string): Promise<StockQuote>;
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { cache,
|
|
1
|
+
import YahooFinance from "yahoo-finance2";
|
|
2
|
+
import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
|
|
3
|
+
import { HttpError, httpGet } from "../infra/http-client.js";
|
|
3
4
|
import { rateLimiter } from "../infra/rate-limiter.js";
|
|
4
|
-
import { StealthBrowser } from "../infra/browser.js";
|
|
5
5
|
import { computeGreeks } from "../tools/options/greeks.js";
|
|
6
|
+
import { InvalidSymbolError } from "./errors.js";
|
|
6
7
|
const BASE_URL = "https://query1.finance.yahoo.com/v8/finance/chart";
|
|
7
8
|
const QUOTE_SUMMARY_URL = "https://query1.finance.yahoo.com/v10/finance/quoteSummary";
|
|
9
|
+
const STALE_QUOTE_MAX_RETRY_AFTER_MS = 1_000;
|
|
10
|
+
let yahooFinance2Client;
|
|
11
|
+
function getYahooFinance2Client() {
|
|
12
|
+
yahooFinance2Client ??= new YahooFinance({
|
|
13
|
+
suppressNotices: ["yahooSurvey", "ripHistorical"],
|
|
14
|
+
});
|
|
15
|
+
return yahooFinance2Client;
|
|
16
|
+
}
|
|
8
17
|
export async function getQuote(symbol) {
|
|
9
18
|
const cacheKey = `yahoo:quote:${symbol}`;
|
|
10
19
|
const cached = cache.get(cacheKey);
|
|
@@ -15,6 +24,7 @@ export async function getQuote(symbol) {
|
|
|
15
24
|
const url = `${BASE_URL}/${encodeURIComponent(symbol)}?interval=1d&range=1d`;
|
|
16
25
|
const data = await httpGet(url, {
|
|
17
26
|
headers: { "User-Agent": "OpenCandle/1.0" },
|
|
27
|
+
maxRetryAfterMs: STALE_QUOTE_MAX_RETRY_AFTER_MS,
|
|
18
28
|
});
|
|
19
29
|
if (data.chart.error) {
|
|
20
30
|
throw new Error(`Yahoo Finance: ${data.chart.error.description}`);
|
|
@@ -43,7 +53,13 @@ export async function getQuote(symbol) {
|
|
|
43
53
|
week52High: meta.fiftyTwoWeekHigh ?? 0,
|
|
44
54
|
week52Low: meta.fiftyTwoWeekLow ?? 0,
|
|
45
55
|
timestamp: Date.now(),
|
|
56
|
+
currency: typeof meta.currency === "string" && meta.currency.trim() !== ""
|
|
57
|
+
? meta.currency.trim().toUpperCase()
|
|
58
|
+
: null,
|
|
46
59
|
};
|
|
60
|
+
if (isZeroResultQuote(quote)) {
|
|
61
|
+
throw new InvalidSymbolError(symbol.toUpperCase(), "yahoo");
|
|
62
|
+
}
|
|
47
63
|
cache.set(cacheKey, quote, TTL.QUOTE);
|
|
48
64
|
return quote;
|
|
49
65
|
}
|
|
@@ -54,6 +70,13 @@ export async function getQuote(symbol) {
|
|
|
54
70
|
throw error;
|
|
55
71
|
}
|
|
56
72
|
}
|
|
73
|
+
function isZeroResultQuote(quote) {
|
|
74
|
+
return (quote.price === 0 &&
|
|
75
|
+
quote.volume === 0 &&
|
|
76
|
+
quote.week52High === 0 &&
|
|
77
|
+
quote.week52Low === 0 &&
|
|
78
|
+
quote.marketCap === 0);
|
|
79
|
+
}
|
|
57
80
|
export async function getHistory(symbol, range = "6mo", interval = "1d") {
|
|
58
81
|
const cacheKey = `yahoo:history:${symbol}:${range}:${interval}`;
|
|
59
82
|
const cached = cache.get(cacheKey);
|
|
@@ -99,11 +122,7 @@ export async function getFundHoldings(symbol) {
|
|
|
99
122
|
return cached;
|
|
100
123
|
try {
|
|
101
124
|
await rateLimiter.acquire("yahoo");
|
|
102
|
-
const
|
|
103
|
-
const url = `${QUOTE_SUMMARY_URL}/${encodeURIComponent(normalizedSymbol)}?modules=${modules}`;
|
|
104
|
-
const data = await httpGet(url, {
|
|
105
|
-
headers: { "User-Agent": "OpenCandle/1.0" },
|
|
106
|
-
});
|
|
125
|
+
const data = await getFundHoldingsSummary(normalizedSymbol);
|
|
107
126
|
const result = data.quoteSummary.result?.[0];
|
|
108
127
|
if (data.quoteSummary.error) {
|
|
109
128
|
throw new Error(`Yahoo Finance: ${data.quoteSummary.error.description ?? data.quoteSummary.error.code ?? "quoteSummary error"}`);
|
|
@@ -120,11 +139,13 @@ export async function getFundHoldings(symbol) {
|
|
|
120
139
|
const weight = normalizeHoldingWeight(holding.holdingPercent);
|
|
121
140
|
if (!holdingSymbol || weight === undefined)
|
|
122
141
|
return [];
|
|
123
|
-
return [
|
|
142
|
+
return [
|
|
143
|
+
{
|
|
124
144
|
symbol: holdingSymbol,
|
|
125
145
|
name: holding.holdingName?.trim() || holdingSymbol,
|
|
126
146
|
weight,
|
|
127
|
-
}
|
|
147
|
+
},
|
|
148
|
+
];
|
|
128
149
|
}),
|
|
129
150
|
sectorWeights: normalizeSectorWeights(result.topHoldings.equityHoldings?.sectorWeightings),
|
|
130
151
|
};
|
|
@@ -141,10 +162,51 @@ export async function getFundHoldings(symbol) {
|
|
|
141
162
|
throw error;
|
|
142
163
|
}
|
|
143
164
|
}
|
|
165
|
+
async function getFundHoldingsSummary(symbol) {
|
|
166
|
+
try {
|
|
167
|
+
return await fetchFundHoldingsSummary(symbol);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
if (!isYahooAuthError(error))
|
|
171
|
+
throw error;
|
|
172
|
+
return fetchFundHoldingsSummaryWithCrumb(symbol);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async function fetchFundHoldingsSummary(symbol) {
|
|
176
|
+
const modules = encodeURIComponent("price,topHoldings");
|
|
177
|
+
const url = `${QUOTE_SUMMARY_URL}/${encodeURIComponent(symbol)}?modules=${modules}`;
|
|
178
|
+
return httpGet(url, {
|
|
179
|
+
headers: { "User-Agent": "OpenCandle/1.0" },
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
async function fetchFundHoldingsSummaryWithCrumb(symbol) {
|
|
183
|
+
const modules = encodeURIComponent("price,topHoldings");
|
|
184
|
+
const { crumb, cookie } = await getYahooCrumb();
|
|
185
|
+
const url = `${QUOTE_SUMMARY_URL}/${encodeURIComponent(symbol)}?modules=${modules}&crumb=${encodeURIComponent(crumb)}`;
|
|
186
|
+
try {
|
|
187
|
+
return await httpGet(url, {
|
|
188
|
+
headers: { "User-Agent": BROWSER_UA, Cookie: cookie },
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (!isYahooAuthError(error))
|
|
193
|
+
throw error;
|
|
194
|
+
clearCrumbCache();
|
|
195
|
+
const fresh = await getYahooCrumb();
|
|
196
|
+
const retryUrl = `${QUOTE_SUMMARY_URL}/${encodeURIComponent(symbol)}?modules=${modules}&crumb=${encodeURIComponent(fresh.crumb)}`;
|
|
197
|
+
return httpGet(retryUrl, {
|
|
198
|
+
headers: { "User-Agent": BROWSER_UA, Cookie: fresh.cookie },
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function isYahooAuthError(error) {
|
|
203
|
+
return error instanceof HttpError && (error.status === 401 || error.status === 429);
|
|
204
|
+
}
|
|
144
205
|
function normalizeHoldingWeight(value) {
|
|
145
|
-
|
|
206
|
+
const numeric = typeof value === "number" ? value : value?.raw;
|
|
207
|
+
if (numeric === undefined || !Number.isFinite(numeric) || numeric <= 0)
|
|
146
208
|
return undefined;
|
|
147
|
-
return
|
|
209
|
+
return numeric > 1 ? roundWeight(numeric / 100) : roundWeight(numeric);
|
|
148
210
|
}
|
|
149
211
|
function normalizeSectorWeights(sectors) {
|
|
150
212
|
if (!sectors?.length)
|
|
@@ -164,6 +226,7 @@ function roundWeight(value) {
|
|
|
164
226
|
}
|
|
165
227
|
// --- Options Chain (v7 API with crumb+cookie auth) ---
|
|
166
228
|
const BROWSER_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
|
|
229
|
+
const YAHOO_RAW_FETCH_TIMEOUT_MS = 10_000;
|
|
167
230
|
let cachedCrumb = null;
|
|
168
231
|
export function clearCrumbCache() {
|
|
169
232
|
cachedCrumb = null;
|
|
@@ -175,14 +238,25 @@ export async function getYahooCrumb() {
|
|
|
175
238
|
// Step 1: Hit fc.yahoo.com to get a session cookie
|
|
176
239
|
const cookieRes = await fetch("https://fc.yahoo.com/t", {
|
|
177
240
|
headers: { "User-Agent": BROWSER_UA },
|
|
241
|
+
signal: yahooRawFetchSignal(),
|
|
178
242
|
});
|
|
179
243
|
const setCookie = cookieRes.headers.get("set-cookie") ?? "";
|
|
180
244
|
const cookie = setCookie.split(";")[0]; // Extract just the cookie value
|
|
245
|
+
if (!cookie) {
|
|
246
|
+
if (!cookieRes.ok) {
|
|
247
|
+
throw new Error(`Yahoo crumb cookie request failed: HTTP ${cookieRes.status} ${cookieRes.statusText}`.trim());
|
|
248
|
+
}
|
|
249
|
+
throw new Error("Yahoo crumb cookie request did not return a session cookie");
|
|
250
|
+
}
|
|
181
251
|
// Step 2: Use the cookie to get a crumb
|
|
182
252
|
const crumbRes = await fetch("https://query2.finance.yahoo.com/v1/test/getcrumb", {
|
|
183
253
|
headers: { "User-Agent": BROWSER_UA, Cookie: cookie },
|
|
254
|
+
signal: yahooRawFetchSignal(),
|
|
184
255
|
});
|
|
185
|
-
|
|
256
|
+
if (!crumbRes.ok) {
|
|
257
|
+
throw new Error(`Yahoo crumb request failed: HTTP ${crumbRes.status} ${crumbRes.statusText}`.trim());
|
|
258
|
+
}
|
|
259
|
+
const crumb = (await crumbRes.text()).trim();
|
|
186
260
|
if (!crumb || crumb.includes("Unauthorized")) {
|
|
187
261
|
throw new Error("Failed to acquire Yahoo Finance crumb");
|
|
188
262
|
}
|
|
@@ -195,14 +269,15 @@ export async function getOptionsChain(symbol, expiration) {
|
|
|
195
269
|
if (cached)
|
|
196
270
|
return cached;
|
|
197
271
|
await rateLimiter.acquire("yahoo");
|
|
198
|
-
const { crumb, cookie } = await getYahooCrumb();
|
|
199
272
|
const dateParam = expiration ? `&date=${expiration}` : "";
|
|
200
|
-
const url = `https://query1.finance.yahoo.com/v7/finance/options/${encodeURIComponent(symbol)}?crumb=${encodeURIComponent(crumb)}${dateParam}`;
|
|
201
273
|
let res = null;
|
|
202
274
|
let fetchError;
|
|
203
275
|
try {
|
|
276
|
+
const { crumb, cookie } = await getYahooCrumb();
|
|
277
|
+
const url = `https://query1.finance.yahoo.com/v7/finance/options/${encodeURIComponent(symbol)}?crumb=${encodeURIComponent(crumb)}${dateParam}`;
|
|
204
278
|
res = await fetch(url, {
|
|
205
279
|
headers: { "User-Agent": BROWSER_UA, Cookie: cookie },
|
|
280
|
+
signal: yahooRawFetchSignal(),
|
|
206
281
|
});
|
|
207
282
|
}
|
|
208
283
|
catch (error) {
|
|
@@ -216,6 +291,7 @@ export async function getOptionsChain(symbol, expiration) {
|
|
|
216
291
|
const retryUrl = `https://query1.finance.yahoo.com/v7/finance/options/${encodeURIComponent(symbol)}?crumb=${encodeURIComponent(fresh.crumb)}${dateParam}`;
|
|
217
292
|
res = await fetch(retryUrl, {
|
|
218
293
|
headers: { "User-Agent": BROWSER_UA, Cookie: fresh.cookie },
|
|
294
|
+
signal: yahooRawFetchSignal(),
|
|
219
295
|
});
|
|
220
296
|
}
|
|
221
297
|
catch (error) {
|
|
@@ -227,9 +303,9 @@ export async function getOptionsChain(symbol, expiration) {
|
|
|
227
303
|
if (!res?.ok) {
|
|
228
304
|
let browserError;
|
|
229
305
|
try {
|
|
230
|
-
const
|
|
231
|
-
if (
|
|
232
|
-
const chain = parseOptionsResponse(
|
|
306
|
+
const fallbackData = await fetchOptionsViaYahooFinance2(symbol, expiration);
|
|
307
|
+
if (fallbackData) {
|
|
308
|
+
const chain = parseOptionsResponse(fallbackData);
|
|
233
309
|
cache.set(cacheKey, chain, TTL.OPTIONS_CHAIN);
|
|
234
310
|
return chain;
|
|
235
311
|
}
|
|
@@ -244,21 +320,26 @@ export async function getOptionsChain(symbol, expiration) {
|
|
|
244
320
|
if (res) {
|
|
245
321
|
const message = `Yahoo Finance options: HTTP ${res.status}`;
|
|
246
322
|
if (browserError instanceof Error) {
|
|
247
|
-
throw new Error(`${message};
|
|
323
|
+
throw new Error(`${message}; yahoo-finance2 fallback failed: ${browserError.message}`);
|
|
248
324
|
}
|
|
249
325
|
throw new Error(message);
|
|
250
326
|
}
|
|
251
327
|
if (browserError instanceof Error) {
|
|
252
328
|
const message = fetchError instanceof Error ? fetchError.message : "Yahoo Finance options: fetch failed";
|
|
253
|
-
throw new Error(`${message};
|
|
329
|
+
throw new Error(`${message}; yahoo-finance2 fallback failed: ${browserError.message}`);
|
|
254
330
|
}
|
|
255
|
-
throw fetchError instanceof Error
|
|
331
|
+
throw fetchError instanceof Error
|
|
332
|
+
? fetchError
|
|
333
|
+
: new Error("Yahoo Finance options: fetch failed");
|
|
256
334
|
}
|
|
257
335
|
const data = await res.json();
|
|
258
336
|
const chain = parseOptionsResponse(data);
|
|
259
337
|
cache.set(cacheKey, chain, TTL.OPTIONS_CHAIN);
|
|
260
338
|
return chain;
|
|
261
339
|
}
|
|
340
|
+
function yahooRawFetchSignal() {
|
|
341
|
+
return AbortSignal.timeout(YAHOO_RAW_FETCH_TIMEOUT_MS);
|
|
342
|
+
}
|
|
262
343
|
/**
|
|
263
344
|
* Compute time to expiry in years from a Yahoo expiration timestamp (midnight UTC).
|
|
264
345
|
* US equity options expire at 4:00 PM ET. During EDT that is 20:00 UTC.
|
|
@@ -340,6 +421,9 @@ function parseOptionsResponse(data) {
|
|
|
340
421
|
const quote = result.quote;
|
|
341
422
|
const underlyingPrice = quote.regularMarketPrice ?? 0;
|
|
342
423
|
const opts = result.options[0];
|
|
424
|
+
if (!opts && underlyingPrice === 0) {
|
|
425
|
+
throw new InvalidSymbolError(result.underlyingSymbol, "yahoo");
|
|
426
|
+
}
|
|
343
427
|
const riskFreeRate = 0.05;
|
|
344
428
|
const expirationTs = opts.expirationDate;
|
|
345
429
|
const expirationDate = new Date(expirationTs * 1000).toISOString().split("T")[0];
|
|
@@ -347,7 +431,14 @@ function parseOptionsResponse(data) {
|
|
|
347
431
|
const mapContract = (c, type) => {
|
|
348
432
|
const strike = c.strike ?? c.strike?.raw ?? 0;
|
|
349
433
|
const iv = c.impliedVolatility ?? c.impliedVolatility?.raw ?? 0;
|
|
350
|
-
const greeks = computeGreeks({
|
|
434
|
+
const greeks = computeGreeks({
|
|
435
|
+
type,
|
|
436
|
+
spot: underlyingPrice,
|
|
437
|
+
strike,
|
|
438
|
+
timeYears,
|
|
439
|
+
iv,
|
|
440
|
+
riskFreeRate,
|
|
441
|
+
});
|
|
351
442
|
return {
|
|
352
443
|
contractSymbol: c.contractSymbol ?? "",
|
|
353
444
|
type,
|
|
@@ -383,37 +474,51 @@ function parseOptionsResponse(data) {
|
|
|
383
474
|
};
|
|
384
475
|
}
|
|
385
476
|
/**
|
|
386
|
-
* Fallback: fetch options data via
|
|
387
|
-
* Bypasses Yahoo's TLS fingerprinting and rate limiting.
|
|
477
|
+
* Fallback: fetch options data via yahoo-finance2 when the raw Yahoo path is blocked.
|
|
388
478
|
*/
|
|
389
|
-
async function
|
|
479
|
+
async function fetchOptionsViaYahooFinance2(symbol, expiration) {
|
|
390
480
|
try {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
// Navigating directly to Yahoo's JSON endpoints still uses the browser's
|
|
394
|
-
// cookies/TLS fingerprint without requiring cross-origin fetch from page JS.
|
|
395
|
-
const dateParam = expiration ? `&date=${expiration}` : "";
|
|
396
|
-
return await StealthBrowser.run(async (page) => {
|
|
397
|
-
await page.goto("https://query2.finance.yahoo.com/v1/test/getcrumb", {
|
|
398
|
-
waitUntil: "domcontentloaded",
|
|
399
|
-
timeout: 15000,
|
|
400
|
-
});
|
|
401
|
-
const crumb = (await page.locator("body").innerText()).trim();
|
|
402
|
-
if (!crumb)
|
|
403
|
-
return null;
|
|
404
|
-
const url = `https://query1.finance.yahoo.com/v7/finance/options/${encodeURIComponent(symbol)}?crumb=${encodeURIComponent(crumb)}${dateParam}`;
|
|
405
|
-
const response = await page.goto(url, {
|
|
406
|
-
waitUntil: "domcontentloaded",
|
|
407
|
-
timeout: 15000,
|
|
408
|
-
});
|
|
409
|
-
if (!response?.ok())
|
|
410
|
-
return null;
|
|
411
|
-
const text = (await page.locator("body").innerText()).trim();
|
|
412
|
-
return JSON.parse(text);
|
|
413
|
-
});
|
|
481
|
+
const result = await getYahooFinance2Client().options(symbol, expiration ? { date: new Date(expiration * 1000) } : undefined);
|
|
482
|
+
return normalizeYahooFinance2OptionsResponse(result);
|
|
414
483
|
}
|
|
415
484
|
catch (error) {
|
|
416
485
|
throw error instanceof Error ? error : new Error(String(error));
|
|
417
486
|
}
|
|
418
487
|
}
|
|
488
|
+
function normalizeYahooFinance2OptionsResponse(data) {
|
|
489
|
+
if ("optionChain" in data)
|
|
490
|
+
return data;
|
|
491
|
+
const options = data.options.map((option) => ({
|
|
492
|
+
expirationDate: toYahooUnixSeconds(option.expirationDate),
|
|
493
|
+
calls: option.calls,
|
|
494
|
+
puts: option.puts,
|
|
495
|
+
}));
|
|
496
|
+
const strikes = [
|
|
497
|
+
...new Set(options
|
|
498
|
+
.flatMap((option) => [...option.calls, ...option.puts])
|
|
499
|
+
.map((contract) => Number(contract.strike))
|
|
500
|
+
.filter((strike) => Number.isFinite(strike))),
|
|
501
|
+
].sort((a, b) => a - b);
|
|
502
|
+
return {
|
|
503
|
+
optionChain: {
|
|
504
|
+
result: [
|
|
505
|
+
{
|
|
506
|
+
underlyingSymbol: data.underlyingSymbol,
|
|
507
|
+
expirationDates: data.expirationDates.map(toYahooUnixSeconds),
|
|
508
|
+
strikes,
|
|
509
|
+
quote: data.quote,
|
|
510
|
+
options,
|
|
511
|
+
},
|
|
512
|
+
],
|
|
513
|
+
},
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
function toYahooUnixSeconds(value) {
|
|
517
|
+
if (value instanceof Date)
|
|
518
|
+
return Math.floor(value.getTime() / 1000);
|
|
519
|
+
if (typeof value === "number") {
|
|
520
|
+
return value > 1_000_000_000_000 ? Math.floor(value / 1000) : value;
|
|
521
|
+
}
|
|
522
|
+
return Math.floor(new Date(value).getTime() / 1000);
|
|
523
|
+
}
|
|
419
524
|
//# sourceMappingURL=yahoo-finance.js.map
|