> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# 构建AI驱动的股票筛选器
- URL: https://www.hubwiz.com/blog/build-an-ai-powered-stock-screener/
- Published: 2025-12-06T11:39:41.000Z
- Updated: 2025-12-06T11:39:41.000Z
- Description: 我花了两个月时间构建了一个代理AI研究工具，运行成本约为10美元，拒绝了大约95%的候选股票，并让我能够将更多精力集中在真正关心的股票上。
- Author: admin
- Tags: AGENT, STOCK RESEARCH, #Import 2026-10-14 14:41

我花了两个月时间构建了一个代理AI研究工具，用于筛选国际股票。它的运行成本约为10美元，拒绝了大约95%的候选股票，并让我能够将更多精力集中在真正关心的股票上。

本文详细介绍了代理AI系统的工作原理、它做得好的地方、它遇到的困难，以及在构建类似东西之前你应该知道的事情。

## 1、问题

白天我在数据工程和信息安全领域工作。

然而，最近我花了很多晚上的时间思考，美国投资者担心赤字、AI泡沫和总体政治不稳定，可以通过分散投资到非美国市场的中盘股来对冲这些风险——例如东京、香港、华沙和吉隆坡等市场，这些市场中有合法、增长中的中小盘公司交易并赚钱，而不严重依赖美国市场和贸易。

由于符合这一理论的股票通常没有被美国分析师充分覆盖，找到和评估它们既困难又需要时间，而我没有时间。这也会花费金钱。Bloomberg终端约3万美元/年。FactSet也差不多。是的，你可以把你的投资组合交给像Fisher这样的经理人，但他们会收取一定费用。

随着AI现在开辟了新的可能性，我想：我能否低成本地构建一个代理AI股票研究工具，帮助我找到和筛选符合我理论的股票并生成轻松的alpha？

## 2、我构建的解决方案

我最终构建的股票评估器使用LangGraph（一个代理协调框架）来运行五阶段工作流程。

![](https://www.hubwiz.com/blog/content/images/2025/12/image-46.png)

完整的代理图工作流

**阶段1：数据收集（并行）**  
四个专业代理同时运行：

- **市场分析师**：价格历史、流动性、RSI/MACD/Bollinger
- **基本面分析师**：市盈率、净资产收益率、负债权益比、现金流等
- **新闻分析师**：最近的文件、公司新闻（Tavily）
- **情绪分析师**：零售热度（StockTwits、Reddit）

这在东京、香港、台湾和其他成熟交易所中效果很好。但在马来西亚、印度尼西亚和大部分东南亚地区效果较差，因为免费的数据源在这些地区的交易所上市数据并不完善。

以下是实际的后备逻辑：

```
def get_financial_metrics(ticker: str) -> dict:  
    """尝试多个来源，合并结果，填补关键空白。"""  
    result = {}  

    # 主要来源：yfinance（免费，通常对于流动性强的股票很好）  
    result = fetch_yfinance(ticker)  

    # 如果关键指标缺失，尝试yahooquery  
    if missing_critical_fields(result):  
        yahoo_data = fetch_yahooquery(ticker)  
        result = merge_keeping_best(result, yahoo_data)  

    # 如果仍然有空白，尝试FMP（如果API密钥可用）  
    if missing_critical_fields(result) and FMP_API_KEY:  
        fmp_data = fetch_fmp(ticker)  
        result = merge_keeping_best(result, fmp_data)  

    # 最后手段：针对特定缺失字段进行网络搜索  
    if missing_critical_fields(result):  
        web_data = search_for_gaps(ticker, result)  
        result = merge_keeping_best(result, web_data)  

    return sanitize_and_validate(result)

```

主要问题：搜索某些股票，特别是那些仍处于标准会计和透明度要求概念中的国家的交易所，返回空的结果集。当这种情况发生时，后续代理可利用的信息就更少了。

**阶段2：综合**  
研究经理尽最大努力处理所有四份报告并撰写摘要。在我早期的代码版本中，此阶段的输出是一篇超过2000字的文章。不受限制的LLM可能会非常冗长。通过积极的提示工程，我将其长度减少到几个要点（“不要写引言”）。

**阶段3：多空辩论（变革性部分）**  
在此阶段，两个对抗代理进行1–2轮辩论。多头得到一个提示，告诉它“为购买提出最强的论点——反驳空头的担忧。”空头则被指示“为避免购买提出最强的论点——并反驳多头的乐观情绪。”

来自汇丰银行（[0005.HK](http://0005.hk/?ref=hubwiz.com)）的例子：

**多头**：“市盈率14.79，低于历史平均水平。40%的营业利润率。610亿美元的自由现金流。这是便宜的，而不是破败的。”

**空头**：“营收增长4.8%是疲软的。每股收益同比下降16.6%。在地缘政治不确定时期在港运营。一家成熟的银行，没有增长故事。坚决拒绝。”

投资组合经理阅读双方的论点并应用评分规则。上述案例中，汇丰银行未能满足增长要求→卖出。

基于辩论的评估结构优于让单个LLM“分析这只股票”。单代理会进行权衡和妥协。他们也可能被你提示中无意的引导语言所影响。对抗代理让他们承诺不同的立场，并允许后续代理清楚地看到辩论的所有方面。

**阶段4：风险规模**  
一旦研究经理完成其输入的综合，三个风险分析师（保守、中立和激进）然后推荐一个仓位规模。即使经过推动，我发现“激进”的一方可能非常谨慎——Gemini似乎被训练得风险规避。但这对我来说没问题。我也很谨慎。

**最终决定**  
在此阶段，投资组合经理设置硬性门槛：

- 财务健康评级 ≥ 50%
- 增长评分 ≥ 50%
- 流动性 ≥ 每日50万美元
- 分析师覆盖率 < 15（更喜欢未被发现的名称）

例如，截至我2025年11月30日的运行，汇丰银行在健康方面得分为62.5%，增长得分为0% → 自动卖出。三星在估值方面表现良好，但有100多名分析师谈论它 → 卖出。

当然，这就是想法。该系统强制执行我关心的规则，并仅显示不违反规则的内容。它节省了我的时间。

在上述情况下，逻辑如下：

```
def make_decision(health_score, growth_score, liquidity, coverage):  
    # 硬性失败 - 任何一项都会使股票不合格  
    if health_score < 0.50:  
        return "SELL", "硬性失败：财务健康 < 50%"  

    if growth_score < 0.50:  
        return "SELL", "硬性失败：增长评分 < 50%"  

    if liquidity < 500_000:  
        return "SELL", "硬性失败：流动性 < 50万美元"  

    if coverage >= 15:  
        return "SELL", "分析师覆盖率过高（未被发现）"  

    # 通过所有门 - 现在检查软因素（估值、风险）  
    return assess_qualitative_factors(...)

```

无论多少辩论都无法改变这些阈值。如果增长为0%，那就是卖出。

## 3、为什么有效

**1\. 它强制纪律**汇丰银行的市盈率为14.79，看起来很便宜。它是汇丰银行——全球银行，家喻户晓，支付股息。人类分析师可能会想，“但它就是汇丰银行。我听了他们的Banyan Tree播客。他们很棒！”AI不关心。增长评分：0%。被拒绝。

如果没有这个系统，我会拒绝汇丰银行吗？我不知道。可能甚至不会想到去查看。系统是对的吗？是的，很可能。如果我担心，我可以在报告中获得所需的所有数据，以便开始检查。

**2\. 多空结构迫使更深入的思考**单一LLM的回应平淡且含糊。多代理辩论迫使每一方做出承诺。这就像维基百科文章（平衡但无聊）与法庭辩论（两个强有力的案例，开放倡导和辩论）之间的区别。

**3\. 全面审计追踪**每个数据点都有来源。每个评分都显示其计算方式。当系统说“健康评分：62.5%（5/12原始，调整为8个可用点）”，你可以看到：

- 它获得了哪5个点
- 哪7个点是N/A（以及原因）
- 精确的数学

信任来自于可以验证。下游AI代理可以看到工作，用户查看最终报告时也能看到。

**4\. 零边际成本**构建之后，使用Gemini免费层级运行100只股票的成本是0美元（每分钟15次请求限制）。我升级到了付费第二层级以加快批量处理和更宽松的API限制，现在300只股票的费用约为10美元。

相比之下：Bloomberg终端是每月2,667美元。

## 4、什么会可靠地失败

**1\. 坏数据污染下游结果**案例研究：YTLPOWR.KL（YTL Power International，马来西亚）

系统在最后一次运行（2025年11月下旬）返回：

- 市盈率：161,103,004,000.00（是的，1610亿）
- 市净率：27,230,309,079.61（270亿）
- 财务健康评分：0%（所有指标N/A）

YTL Power是一家糟糕的公司吗？我不知道。免费API不涵盖马来西亚股票。yfinance抓取了损坏的数据，FMP返回了空响应，EODHD在此次运行中没有内容（可能是另一个错误，但其他大多数股票运行正常）。

系统正确标记了这些为异常并拒绝了股票。但它是因为数据缺口而拒绝的，而不是因为基本面差。我没有任何关于实际公司的信息。

**教训**：免费API在成熟市场中表现良好。对于新兴市场（马来西亚、印度尼西亚、泰国等），你需要付费来源或必须将结果视为低置信度标志以供手动研究。

**2\. 系统过于冗长**早期报告超过2000字。每只股票都是如此。多头代理会写道：

“基于对财务报表的全面分析，考虑定量指标和定性因素，同时承认前瞻性预测的固有不确定性…”

我不得不添加提示，如：

- “不要写引言”
- “不要总结你的总结”
- “使用项目符号，而不是段落”
- “每条回复最多300字”

即使有这些限制，报告仍然超过800字。LLM喜欢听到自己说话。

**3\. 大盘股有时会偷偷通过**理论：找到“未被发现”的股票（分析师覆盖率 < 15）。

这对中盘股有效。但对于大盘股，搜索并不总是那么有用：

**腾讯（**[**0700.HK**](http://0700.hk/?ref=hubwiz.com)**）**：“4000亿美元市值…但只有12名分析师由yfinance跟踪…一定是未被发现的！”

显然，腾讯并不是未被发现的。分析师数量只是我计数的方式（由yfinance跟踪的英语分析师）。

**修复**：我添加了市值阈值（>500亿美元 = 自动“高覆盖率”假设）。但这只是一个补丁，不是解决方案。真正的问题：系统偏爱大盘股，因为你可以找到它们的数据。目前，马来西亚真正冷门的中盘股存在于数据沙漠中，我的股票评估器在处理它们时遇到了困难。

**4\. 语言障碍是不可逾越的**对于韩国、日本或中国股票，本地情绪很重要。但是：

- StockTwits：仅限英文，以美国为中心
- Reddit：主要是英文
- 本地论坛：需要API访问和我无法拥有的语言技能

结果：大多数非美国股票的“市场情绪”部分说“无法评估本地情绪”。

如果三星在韩国论坛上受到抨击，AI代理可能不知道，除非我手动检查（这违背了让AI代理完成工作的初衷）。

**4\. 内存隔离花费的时间比预期的更长**早期版本显示了一个持续的错误，分析佳能时会污染汇丰银行的分析。AI会在讨论汇丰银行（一家银行）时引用佳能的芯片短缺。

修复方法：

```
# 之前：全局内存（错误）  
bull_memory = ChromaDB(collection="bull_analysis")  # 所有股票共享  
bear_memory = ChromaDB(collection="bear_analysis")

```

```
# 之后：股票特定命名空间（正确）  
def create_memories(ticker: str):  
    safe_name = ticker.replace(".", "_")  # 0005.HK → 0005_HK  
    return {  
        "bull": ChromaDB(collection=f"{safe_name}_bull"),  
        "bear": ChromaDB(collection=f"{safe_name}_bear"),  
        "risk": ChromaDB(collection=f"{safe_name}_risk")  
    }

```

现在每只股票都有隔离的内存。佳能的分析不会泄露到汇丰银行的分析中。如果你构建这样的系统，请密切关注保存了什么以及如何保存，以及数据在生成过程中如何清除，以及何时清除。

**5\. 速度不是功能**对于300只股票：

- 快速模式：6–12小时
- 标准模式：16–30小时（随着代码演变而变化）

即使在快速模式下，这也很慢。一个拥有Bloomberg的人可以在30分钟内扫描50只股票，并做一份不错的作业。

权衡：AI很细致（可能太细致了），但目前不够快。

## 5、我会有所不同（建议）

**1\. 更好的数据源（可选的未来扩展）**我花了60%的时间在提示工程上。我应该花60%的时间寻找更好的数据源。

“好”和“优秀”分析之间的差异是数据质量，而不是代理架构。

**对于想要扩展这个的人**：该系统设计为使用免费API以保持可访问性。但如果你认真对待新兴市场，付费来源会有帮助：

- [Polygon.io](http://polygon.io/?ref=hubwiz.com)（国际覆盖）
- Koyfin（非专业人士每月20美元）
- Alpha Vantage高级版
- 公司IR网站爬虫（自己构建）

目标是保持核心系统免费和开源。付费数据应该是可插拔的扩展，而不是必需品。如果你为这些来源构建连接器，请创建一个pull request——但确保它们是可选依赖项。别忘了为一切编写测试（坏的或恶意的输入、损坏的API、断开的网络连接、超时、速率限制、异常处理等等）。

**2\. 在辩论之前添加数据质量检查**在多空辩论之前，添加一个代理说：

“12个财务指标中有8个可用。数据质量：良好。继续。”  
或者  
“12个财务指标中有2个可用。数据质量：差。标记为人工审查。”

这会让我避免分析YTL Power（市盈率数据损坏的股票）。

实现：

```
def check_data_quality(metrics: dict) -> str:  
    total_fields = 12  # 市盈率、净资产收益率、资产回报率、负债权益比、收入、每股收益等  
    available = sum(1 for v in metrics.values() if v is not None)  
    coverage = available / total_fields  

    if coverage >= 0.66:  # 8+ of 12 fields  
        return "GOOD"  
    elif coverage >= 0.33:  # 4-7 of 12 fields  
        return "MARGINAL"  
    else:  # < 4 fields  
        return "POOR"

```

```
# 然后在主流程中：  
data_quality = check_data_quality(financial_metrics)  
if data_quality == "POOR":  
    return {  
        "decision": "REJECT",  
        "reason": "数据分析数据不足",  
        "metrics_available": f"{available}/{total_fields}"  
    }

```

在浪费计算资源进行无价值辩论之前运行。

**3\. 使用结构化输出（在大规模筛选时）**我的代理返回markdown文本。这对于人工研究个别股票来说是可读的，效果很好。

**对于批量筛选**（筛选300只股票以找到15只买入），我希望有人添加JSON输出作为选项：

```
{  
  "ticker": "0005.HK",  
  "company": "汇丰控股",  
  "decision": "卖出",  
  "conviction": "高",  
  "health_score": 62.5,  
  "growth_score": 0.0,  
  "position_size_pct": 0,  
  "hard_fails": ["growth_score"],  
  "key_risks": ["收益下降", "地缘政治风险"],  
  "rationale": "通过健康门但未满足增长要求（0% vs 50%阈值)"  
}

```

然后我们可以程序化过滤：`jq '.[] | select(.decision == "BUY")' results.json`.

保留markdown用于详细报告。添加JSON用于程序化过滤。两者都有其用途。

**4\. 仔细选择你的市场**我想要一个通用的非美国股票分析器。我学到的是：没有这样的东西。

- 香港/日本/台湾：出色的API覆盖，系统有效
- 马来西亚/印度尼西亚/泰国：数据荒漠，系统挣扎
- 韩国：中间地带（数据不错，语言障碍）
- 大多数欧洲国家：稳固
- 印度、越南、巴西：无法访问美国散户投资者

**教训**：为你要交易的市场构建。不要试图解决所有问题。

## 6、这是否有用？

**这个系统做得好的地方**：

- 将300个候选者筛选到十几个值得调查的
- 捕获许多价值陷阱（便宜是有原因的）
- 强制纪律（硬性门槛防止情绪交易）
- 每次运行成本0–10美元，而不是每年24,000美元

**它不能做到**：

- 替代人类判断（它不能）
- 处理坏数据（垃圾输入，垃圾输出）
- 在没有付费API的情况下处理新兴市场
- 实时交易决策（它太慢）

把它想象成这样：如果你雇用一个实习生来做初步的股票筛选，这个系统完成了实习生的工作。它不会取代资深分析师，也不会找到数据中没有的机会。但它会让你避免浪费时间在明显的拒绝上。

## 7、代码是开源的

[仓库链接](https://github.com/rgoerwit/ai-investment-agent?ref=hubwiz.com)。

**包含的内容**：

- 完整的LangGraph工作流（6种代理类型）
- 多源数据获取器（yfinance、FMP、EODHD、Tavily）
- 450多个单元测试
- 详细的设置说明

**要求**：

- Python 3.12+
- Google Gemini API密钥（免费层级可用）
- 基本的命令行技能
- 可选：Tavily、FMP、EODHD密钥以获得更好的数据

**你可以用它做什么**：

- 筛选你自己的观察清单
- 修改理论（更改阈值，增删规则）
- 交换更好的数据源（请这样做，但使其成为可选）
- 研究多代理系统在实践中的运作方式

**你不应该做**：

- 盲目信任它用于真实资金
- 期望第一天就完美
- 当推荐不起作用时责怪我

## 8、最终想法

我构建的代理AI股票评估器的真实价值不在于找到下一个10倍股。而在于有一个系统说“不”给285只股票，让我可以将时间花在剩下的15只上。这值得每月10美元。

如果你在构建类似的东西，我的建议是：首先专注于数据质量，然后在浪费计算资源于垃圾输入之前添加数据置信度检查。如果我再写一次，我可能会使用结构化输出而不是markdown。

对于新兴市场，考虑构建付费API连接器——但保持它们的可选性，这样系统对所有人来说仍然是可访问的，成本低廉。

---

原文链接：[Building an Open-Source Agentic AI Equity Research Tool](https://medium.datadriveninvestor.com/building-an-open-source-agentic-ai-equity-research-tool-172783ed6961?gi=5bdb04a78665&source=home%5Ffor%5Fyou---------22-98--------------------025e1be9%5F21de%5F40fe%5F9170%5F2d4c59be7b3c-------15-------)

汇智网翻译整理，转载请标明出处