高效提取财报数据:基于TradingView新闻源的AI Skill实战

上周帮团队做财报汇总,发现TradingView上每条新闻都要手动点开、登录、找数据。明明有一堆表格,却要复制粘贴10次。于是写了个AI Skill,把这件事做成自动化的技能包。今天拆给你看——读完你也能写一个,用到股票、基金、宏观数据提取上。

这个 Skill 解决什么具体问题

问题:TradingView 聚合了 Reuters、Dow Jones 等主流财经新闻,但财报数据(营收、利润、EPS)散落在新闻正文或附表中,手动提取效率低、容易漏项。

解决:通过 Tavily 搜索 + 定制 Prompt,自动抓取指定公司(如 Imasen Elec)的最新财报新闻,并结构化输出关键指标。

financial analyst extracting data from news articles

Skill 的触发条件和适用场景

  • 触发条件:开发者主动调用(命令行或API),传入公司名称(如 "Imasen Elec")和年份区间(如 "2025/26")。
  • 适用场景
    • 每日/每周生成持仓公司财报速览
    • 事件驱动系统(监听财报发布日期自动触发)
    • 对比多家公司财务表现的研究报告
  • 不适用场景:需要实时 tick 数据或深度财务模型(这个 Skill 只做一级提取)。

完整 Skill 结构(SKILL.md 示例)

每个 Skill 本质上是一个可复用模块。我的习惯是:一个目录 + 一个 SKILL.md + 一个主函数脚本。目录结构如下:

text
1 2 3 4 5
financial-fetch-skill/
├── SKILL.md              # 技能描述与触发配置
├── fetch_earnings.py     # 核心逻辑(tavily搜索 + prompt提取)
├── config.yaml           # API密钥、默认参数
└── requirements.txt      # 依赖

SKILL.md 内容(可直接复制)

markdown
1 2 3 4 5 6 7 8
# SKILL:财报数据提取器

## 目标
根据公司名称和财年,从 TradingView 新闻中提取营收、净利润、EPS 等财务指标,返回结构化 JSON。

## 触发方式
```bash
python fetch_earnings.py --company "Imasen Elec" --year "2025/26"

输入参数

  • company: 字符串,公司全名或股票代码
  • year: 字符串,财年标识,如 "2025/26"
  • source: 可选,默认 "tradingview",预留扩展

输出格式

json
1 2 3 4 5 6 7 8 9
{
  "company": "Imasen Elec",
  "period": "2025/26",
  "revenue": {"value": 123456, "currency": "JPY", "unit": "million"},
  "net_income": {"value": 7890, "currency": "JPY", "unit": "million"},
  "eps": {"value": 54.2, "currency": "JPY"},
  "source_url": "https://www.tradingview.com/news/...",
  "extracted_at": "2026-06-19T07:00:16Z"
}

使用示例

fetch_earnings.py 中的 main() 函数。

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

## 实际案例演示

下面我用 Imasen Elec 2025/26 财报数据作为例子,完整跑一遍提取流程。

### 1. 编写搜索函数(Tavily API)

```python
# fetch_earnings.py 核心片段
import os
import json
from tavily import TavilyClient, MissingAPIKeyError

client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))

def search_financial_news(company: str, year: str) -> list:
    """搜索指定公司的财报新闻,返回页面内容列表"""
    query = f"{company} {year} results site:tradingview.com"
    response = client.search(
        query=query,
        search_depth="advanced",
        max_results=5,
        include_raw_content=True  # 必须,否则拿不到正文
    )
    return [r["raw_content"] for r in response["results"] if r["raw_content"]]

为什么这样写?

  • site:tradingview.com 限定源,避免非金融网站干扰。
  • include_raw_content=True 取到新闻正文,否则只有摘要。
  • search_depth="advanced" 提升召回率,尤其当新闻刚发布时。

2. 设计 Prompt(差 vs 好)

差 Prompt(新手经常写)

text
1
"请从以下新闻中提取财报数据。"

结果:模型返回一段散文,没有数字,甚至可能说“未提供”。

好 Prompt(我的优化版)

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
你是一个金融数据提取器。给定一篇关于财报的新闻文本,你需要提取以下字段并返回 JSON 格式:
- revenue: 营收,包括数值、货币和单位(如 million/billion)
- net_income: 净利润
- eps: 每股收益
- currency: 货币代码(如 JPY, USD)
- fiscal_period: 所涉财年

输出格式严格如下:
{
  "revenue": {"value": 123456.0, "currency": "JPY", "unit": "million"},
  ...
}

如果某个字段在文本中未出现,设为 null。不要编造数据。

新闻文本:
{{TEXT}}

效果对比
| 维度 | 差 Prompt | 好 Prompt |
|------|-----------|-----------|
| 结构化程度 | 无结构,需后续解析 | 直接输出 JSON,可程序消费 |
| 字段完整度 | 可能只输出一个数字 | 明确列出所有目标字段 |
| 稳健性 | 易编造不存在的数据 | 未出现的字段明确为 null |

原理:差 Prompt 没有给模型示例输出格式,也没有限定范围。好 Prompt 使用“提取器”角色、严格JSON Schema、以及“不要编造”指令,让模型知道这是信息抽取任务而非对话。

3. 完整提取函数

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
def extract_financials(full_text: str) -> dict:
    # 使用 LangChain 或直接调用 OpenAI
    from openai import OpenAI
    client = OpenAI()
    
    prompt = f"""你是一个金融数据提取器。给定一篇关于财报的新闻文本,你需要提取以下字段并返回 JSON 格式:
- revenue: 营收,包括数值、货币和单位(如 million/billion)
- net_income: 净利润
- eps: 每股收益
- currency: 货币代码(如 JPY, USD)
- fiscal_period: 所涉财年

输出格式严格如下:
{{
  "revenue": {{"value": 123456.0, "currency": "JPY", "unit": "million"}},
  "net_income": {{"value": 7890.0, "currency": "JPY", "unit": "million"}},
  "eps": {{"value": 54.2, "currency": "JPY"}},
  "fiscal_period": "2025/26"
}}

如果某个字段在文本中未出现,设为 null。不要编造数据。

新闻文本:
{full_text}
"""
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)

4. 主流程串联

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
def main(company: str, year: str):
    # 1. 搜索新闻
    texts = search_financial_news(company, year)
    if not texts:
        print(f"未找到 {company} {year} 的财报新闻")
        return
    
    # 2. 取第一篇最相关的完整新闻
    full_text = texts[0]
    
    # 3. 提取结构化数据
    result = extract_financials(full_text)
    
    # 4. 补充元数据
    result["company"] = company
    result["source_url"] = "通过 Tavily 搜索结果"  # 实际可从 response 中获取
    result["extracted_at"] = "2026-06-19T07:00:16Z"
    
    print(json.dumps(result, indent=2, ensure_ascii=False))

if __name__ == "__main__":
    main("Imasen Elec", "2025/26")

运行输出(示意):

json
1 2 3 4 5 6 7 8 9
{
  "revenue": {"value": 142350, "currency": "JPY", "unit": "million"},
  "net_income": {"value": 7850, "currency": "JPY", "unit": "million"},
  "eps": {"value": 54.2, "currency": "JPY"},
  "fiscal_period": "2025/26",
  "company": "Imasen Elec",
  "source_url": "https://www.tradingview.com/news/reuters.com,2026-06-19:newsml_XB0UNJTVZ:0-table-imasen-elec-2025-26-parent-results/",
  "extracted_at": "2026-06-19T07:00:16Z"
}

复用和组合技巧

变体1:批量提取(多公司)

bash
1
python batch_extract.py --companies "Toyota, Sony, Imasen" --year "2025/26"

search_financial_news 中循环调用即可,注意控制 TPM 限流。

变体2:集成到自动化报表系统

这个 Skill 可以嵌入 GitHub Actions 或 Airflow DAG:

yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# .github/workflows/weekly_earnings.yml
name: Weekly Earnings Extraction
on:
  schedule:
    - cron: "0 8 * * 1"  # 每周一8点
jobs:
  fetch:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run Skill
        env:
          TAVILY_API_KEY: ${{ secrets.TAVILY_API_KEY }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        run: python fetch_earnings.py --company "Imasen Elec" --year "2025/26" > result.json
      - uses: actions/upload-artifact@v4
        with:
          name: earnings-data
          path: result.json

变体3:扩展到宏观数据提取

将 Prompt 中的字段改成“GDP增长率、失业率”等,同样结构可用于拉取宏观经济新闻。

核心原则:把“数据提取”拆解为固定的、可复用的功能模块,本质上这是一个 Skill 的骨架。你可以替换搜索源(比如用 NewsAPI)、替换 Prompt 目标,但框架不变。

最后

这个 Skill 写完之后,我每天至少省出 20 分钟手动复制粘贴。如果你也做金融自动化,或者需要频繁从特定网站提取结构化数据,试试把这个思路套过去。记住:先定义输出 schema,再写 Prompt,最后做搜索。反过来大概率会失败。

文中所有代码片段均可直接复制到本地运行(需安装 tavily-python、openai)。如果你有更好的优化思路,欢迎留言讨论。