* feat: harden alphasift data source routing
* fix(review-feedback-1680): Keep the sample AlphaSift pin in sync and Avoid circuit-breaking
* fix(review-feedback-1680): Defer half-open health checks until a source is attempted and Treat
* fix(review-feedback-1680): fix only bypasses this branch for fetchers that opt into allow empty
* fix(review-feedback-1680): Avoid accepting truncated Tencent histories
* fix(review-feedback-1680): 修正 .env.example 的 AlphaSift 快照源默认说明,并避免在 docs/CHANGELOG.md
* fix(review-feedback-1680): src/config.py、src/services/alphasift service.py
* fix(review-feedback-1680): requirements.txt、src/config.py、.env.example、src/services/alphasift
* fix(review-feedback-1680): 修复 TencentFetcher 对显式历史窗口的处理问题
* fix(review-feedback-1680): Check the cap was hit before rejecting Tencent history
* fix(review-feedback-1680): Use Tencent's hyphenated date format and Convert Tencent daily volume
* fix(review-feedback-1680): Accept the executor timeout argument and preserve capped windows with
* fix: limit empty daily data opt-in behavior
* docs: restore AlphaSift 3.22 changelog entry
* feat: adapt AlphaSift hotspot topics
* fix(review-feedback-1635): preserve cached hotspots when refresh returns no rows and Avoid
* fix(review-feedback-1635): Reload detail when refreshing the selected hotspot and Fall back when
* fix(review-feedback-1635): update by the requested topic or a request token
* fix(review-feedback-1635): preserve analysis when optional serve startup fails and Fall back when
* fix(review-feedback-1635): 当前 CI 状态为 failure,且 backend-gate 为 cancelled、docker-build 为 skipped
* fix(review-feedback-1635): 让 backend-gate / docker-build 在当前 head 上完成并通过,或给出可接受的维护者级豁免说明
* fix(review-feedback-1635): 当前 CI 仍未闭环:结构化事实显示 backend-gate 被取消、docker-build skipped
* fix(review-feedback-1635): 修复 hotspot detail 的上游 schema 容错问题,并让当前 head 的阻断 CI 重新跑通
* fix(review-feedback-1635): docs/CHANGELOG.md:当前 diff 不是在 [Unreleased] 扁平格式下追加本 PR
* fix(review-feedback-1635): CI 闭环未完成:结构化事实显示当前 CI 状态为 failure,backend-gate cancelled、docker-build
* fix(review-feedback-1635): 让当前 head 的阻断型 CI 完整通过,并修正文档中的 AlphaSift commit hash 不一致
* fix(review-feedback-1635): CI 仍未在当前 head 完整通过:结构化事实显示
* fix(review-feedback-1635): 修复 docs/CHANGELOG.md 对主线既有 [Unreleased] 条目的删除,并补齐 AlphaSift
* fix(review-feedback-1635): Accept slash-containing hotspot topics
* fix(review-feedback-1635): Try industry constituents for industry hotspots
* fix(review-feedback-1635): Clear old hotspot details when loading a new topic and preserve the
* test: isolate main schedule environment
* chore: clean AlphaSift PR scope
* fix: respect AlphaSift hotspot fallbacks
- EfinanceFetcher: switch ETF from ef.fund.get_quote_history (NAV only)
to ef.stock.get_quote_history (full OHLCV) so ETFs get proper
open/high/low/close/volume/amount data instead of zeros
- Remove obsolete NAV column mappings from _normalize_data
- Pin tiktoken>=0.8.0,<0.12.0 to avoid 'Unknown encoding cl100k_base'
plugin registration issue in tiktoken 0.12.0
Fixes#541Fixes#527Fixes#537
* feat: multi-channel LLM support with visual channel editor
- Add three-tier LLM config: LITELLM_CONFIG (YAML) > LLM_CHANNELS (env) > legacy keys
- Each channel gets independent base_url / api_key / models (no OPENAI_BASE_URL conflict)
- Support DEEPSEEK_API_KEY as standalone provider (auto-infers deepseek-chat model)
- Add LLMChannelEditor component with 9 presets (AIHubmix/DeepSeek/Dashscope/GLM/Moonshot/SiliconFlow/OpenRouter/Gemini/Custom)
- Expand config_registry with ~50 new fields for web settings coverage
- Rewrite .env.example AI section with clear quick-start guide (Scenario A vs B)
- Add litellm_config.example.yaml template
- Add PyYAML dependency for YAML config support
- Full backward compatibility: existing single-key configs work unchanged
* chore: replace placeholder key values with empty defaults in .env.example
* fix: resolve ESLint errors in LLMChannelEditor and HomePage
* refactor: use native litellm deepseek/ provider and extract shared LLM helpers
- Replace openai/deepseek-* + manual api_base with deepseek/ prefix (litellm
natively resolves DEEPSEEK_API_KEY and base_url)
- Extract duplicated _get_api_keys_for_model and _extra_litellm_params from
analyzer.py and llm_adapter.py into shared functions in config.py
- Update litellm_config.example.yaml to use deepseek/ prefix
- Thinking mode (deepseek-chat opt-in, deepseek-reasoner auto) unaffected:
get_thinking_extra_body uses model short name stripped of provider prefix
* fix: migrate _call_gemini to google-genai SDK for thought_signature support (Fixes#440, Refs #421)
- Replace deprecated google-generativeai with google-genai in llm_adapter.py
- Add base64 round-trip for thought_signature (bytes <-> str) for Gemini 3 multi-turn tool calls
- Fix to_gemini_declaration() to use JSON Schema lowercase types (object/string) for parameters_json_schema
- Add base64 decode error handling for robustness
- Add google-genai>=1.0.0 to requirements.txt; keep google-generativeai for analyzer/image_stock_extractor
* test: update test_gemini_declaration for JSON Schema lowercase types
* fix: use role="tool" for function response per Gemini API docs (review feedback)
- Add trading_calendar module with exchange-calendars for A/HK/US markets
- Per-stock filtering: analyze only stocks whose markets are open today
- Add TRADING_DAY_CHECK_ENABLED config and --force-run CLI override
- Add is_hk_stock_code to data_provider public API
- Update CHANGELOG, full-guide, README, .env.example
* feat: Add image stock code extraction, Anthropic API, and Pytdx config (Fixes#257)
- Add POST /api/v1/stocks/extract-from-image with Vision LLM (Gemini/Anthropic/OpenAI)
- Add image_stock_extractor service with 60s timeout, rate limit (10/min), X-Forwarded-For support
- Add ImageStockExtractor UI in Settings for upload and merge-to-watchlist
- Add ANTHROPIC_API_KEY, ANTHROPIC_MODEL to config and analyzer fallback chain
- Add PYTDX_HOST, PYTDX_PORT, PYTDX_SERVERS for custom Pytdx server
- Add OPENAI_VISION_MODEL for image-only models
- Handle 409 conflict in merge flow with user-friendly message
* fix: resolve TypeScript build error in stocks.ts (avoid Record<> generic parsing)
* feat: Redis rate limiter, API field unification, anthropic_max_tokens
- Add rate_limiter.py: Memory + Redis implementations for extract-from-image
- Integrate get_extract_rate_limiter() in stocks.py; remove image param, keep file only
- Add anthropic_max_tokens config for analyzer
- Update .env.example, config_registry, full-guide, CHANGELOG
- Add redis>=5.0 as optional dependency
* refactor: rename GeminiAnalyzer to LLMAnalyzer for multi-backend clarity
* revert: restore GeminiAnalyzer naming (keep original upstream convention)
* docs: add image extraction and from-image-add usage to README
* fix: Anthropic runtime fallback to OpenAI; remove Redis rate limiter
- Init both Anthropic and OpenAI at startup so Anthropic 429/network glitch can fall back to OpenAI
- Check Anthropic before OpenAI in _call_api_with_retry to preserve priority
- Remove Redis rate limiter per review; keep in-memory only
* remove rate limiter for extract-from-image per review
- Delete rate_limiter.py; extract-from-image has no rate limiting
- Remove Request param and 429 response from stocks endpoint
- Update docs to drop rate limit mentions
- requirements: Added `json-repair` dependency for JSON validation and repair.
- analyzer: Utilized `repair_json` function to ensure JSON strings are correctly formatted before processing.
This enhancement improves the robustness of JSON handling in the analysis workflow.
- Add triple-source fallback for A-share data (EM → Sina → Tencent)
- Add multi-source fallback for chip distribution (Akshare → Tushare → Efinance)
- Fix efinance ETF API parameter errors and OHLC data completion
- Fix tushare index realtime quote code format (sh/sz prefix)
- Fix stock name display issue showing code instead of name
- Upgrade SerpAPI to Google search with Knowledge Graph support
Fixes#206, #171, #139
Related #207
#minor
Resolve conflicts in config.py and notification.py:
- config.py: Merge realtime quote configuration and Discord bot status
- notification.py: Add markdown2 import and enhance single stock report with risk alerts, catalysts, and operation points