Skip to content

Latest commit

 

History

History
124 lines (94 loc) · 6.22 KB

File metadata and controls

124 lines (94 loc) · 6.22 KB

stocklens/search/ — 股票领域搜索壳

职责

围绕 querybus.SearchProvider股票领域薄壳:股票代码识别(A股 / 港股 / 美股 / ETF / 指数)、市场感知的查询模板、5 维度情报并发搜索、新闻时效策略 → news_window_days、价格兜底搜索。

通用搜索能力(cache / fall-over / 时间窗过滤 / 通用情报报告渲染)已经下沉到 querybus,此处不重复。

文件清单

文件 职责 行数
stock_search_service.py StockSearchService 主类 + STOCK_INTEL_DIMENSIONS + 进程级 singleton (get_stock_search_service / configure_stock_search_service / reset_stock_search_service) ~580
__init__.py 重新导出 StockSearchService + SearchResponse / SearchResult(来自 querybus) ~25

旧的 1135 行 search_service.py 已在 querybus 拆分(Commit 3)中整体删除,不留 shim;所有调用点已直接改造为新 API。

核心类

StockSearchService(stock_search_service.py)

构造

from querybus import SearchProvider
from stocklens.search import StockSearchService

provider = SearchProvider(tavily_keys=[...], ...)
service = StockSearchService(
    provider=provider,
    news_max_age_days=3,
    news_strategy_profile="short",   # ultra_short / short / medium / long
)

关键方法

  • search_stock_news(stock_code, stock_name, max_results=5, focus_keywords=None) -> SearchResponse
    • A 股 / 港美股自动切换中英文 query 模板
    • provider.search() → cache → manager → filter
  • search_stock_events(stock_code, stock_name, event_types=None) -> SearchResponse
    • 默认事件:港美股 = earnings report / insider selling / quarterly results,A 股 = 年报预告 / 减持公告 / 业绩快报
  • search_comprehensive_intel(stock_code, stock_name, max_searches=3) -> Dict[str, SearchResponse]
    • 5 维度并发:latest_news / market_analysis / risk_check / earnings / industry
    • ETF / 指数 vs 个股自动切 query
    • 失败时自动放宽窗口到 7 天再试一次
    • 结果跨维度去重(标题前 50 字符为 key)
    • STOCKLENS_SEARCH_WORKERS 控制并发(默认 5)
  • format_intel_report(intel_results, stock_name) -> str
    • 委托给 querybus.SearchProvider.format_intel_report + STOCK_INTEL_DIMENSIONS
  • search_stock_price_fallback(stock_code, stock_name, max_attempts=3, max_results=5) -> SearchResponse
    • 数据源全挂时的 web 兜底搜索
  • search_stock_with_enhanced_fallback(...) — 组合 news + price 的便利方法
  • format_price_search_context(response) -> str — 兜底结果 → AI prompt 上下文

静态分类器

  • _is_foreign_stock(code) -> bool — 港股 / 美股识别(/^[A-Za-z]{1,5}(\.[A-Za-z])?$/ + hk 前缀 + 5 位纯数字)
  • is_index_or_etf(code, name) -> bool — A 股 ETF 前缀 + 美股指数 (is_us_index_code) + 港美股 ETF 名称关键词

进程级 singleton

from stocklens.search import (
    configure_stock_search_service,   # 启动时安装实例
    get_stock_search_service,         # 业务代码读取(带懒加载兜底)
    reset_stock_search_service,       # 配置 reload 后清空
)

API 层在 api/app.py 的 lifespan 中调用 configure_stock_search_service(...);业务代码(agent 工具、pipeline)通过 get_stock_search_service() 读取。CLI / Bot 入口若没经过 lifespan,第一次调用 get_stock_search_service() 会自动从 get_config() 构造一个备选实例。

STOCK_INTEL_DIMENSIONS

STOCK_INTEL_DIMENSIONS = [
    DimensionSpec(key="latest_news",    label="📰 Latest news"),
    DimensionSpec(key="market_analysis", label="📈 Analyst view"),
    DimensionSpec(key="risk_check",     label="⚠️ Risk check"),
    DimensionSpec(key="earnings",       label="📊 Earnings outlook"),
    DimensionSpec(key="industry",       label="🏭 Industry view"),
]

如果未来要换 emoji / 顺序,只改这一处。

依赖关系

  • 依赖:querybustickbridge.codes.us_index.is_us_index_codestocklens.config.settingsstocklens.utils.concurrency.get_pool_workers
  • 被依赖:
    • stocklens/pipeline/orchestrator.py — 流水线编排时构造一次
    • stocklens/pipeline/data_collector.py / analysis_flow.pyis_index_or_etf 静态分类
    • stocklens/agent/tools/search_tools.pybuild_search_tools(service) DI 工厂
    • stocklens/services/system_config_service.py — config reload 时调 reset_stock_search_service()
    • api/app.py lifespan — 启动时安装为进程级 singleton

配置项

变量 默认值 说明
TAVILY_API_KEYS Tavily 搜索 Key(逗号分隔,多 key 负载均衡)
SERPAPI_API_KEYS SerpAPI Key
BOCHA_API_KEYS 博查搜索 Key
MINIMAX_API_KEYS MiniMax Key
BRAVE_API_KEYS Brave Search Key
SEARXNG_BASE_URLS SearXNG 实例 URL 列表
NEWS_MAX_AGE_DAYS 3 新闻最大时效
NEWS_STRATEGY_PROFILE short 时效策略 (ultra_short=1d / short=3d / medium=7d / long=30d)
STOCKLENS_SEARCH_WORKERS 5 多维度并发线程数

注意事项

  • 不配置任何搜索 Key 也能运行:querybus 默认开启 Akshare 兜底(东方财富免费新闻)。
  • 多 Key 配置(逗号分隔)由 querybus 的 BaseSearchProvider 处理负载均衡 + 错误计数,业务层无需感知。
  • 新闻过滤会丢弃日期未知的结果(宁缺毋滥),但 filter_by_time_window 会在数量不够时把 undated 结果标记为 "recent (date unknown)" 补足。
  • 不要直接 from querybus.providers.* import —— CLAUDE.md 已禁止;所有股票业务一律走 StockSearchService

batch_search 并发化(2026-05)

StockSearchService.batch_search(stocks, ..., max_concurrency=2) 替代之前的纯串行 + 1s sleep 实现:

  • 默认 max_concurrency=2:用 ThreadPoolExecutor fan-out,每线程在调用前 sleep(delay_between/max_concurrency) 维持上游限流礼貌
  • max_concurrency=1:完全等价于旧的 strict-sequential 行为(向后兼容)
  • 10 只股票的 batch_search 总耗时从 ~10s 降至 ~3s(max_concurrency=2 时)