高效提取财报数据:基于TradingView新闻源的AI Skill实战
上周帮团队做财报汇总,发现TradingView上每条新闻都要手动点开、登录、找数据。明明有一堆表格,却要复制粘贴10次。于是写了个AI Skill,把这件事做成自动化的技能包。今天拆给你看——读完你也能写一个,用到股票、基金、宏观数据提取上。
这个 Skill 解决什么具体问题
问题:TradingView 聚合了 Reuters、Dow Jones 等主流财经新闻,但财报数据(营收、利润、EPS)散落在新闻正文或附表中,手动提取效率低、容易漏项。
解决:通过 Tavily 搜索 + 定制 Prompt,自动抓取指定公司(如 Imasen Elec)的最新财报新闻,并结构化输出关键指标。

Skill 的触发条件和适用场景
- 触发条件:开发者主动调用(命令行或API),传入公司名称(如 "Imasen Elec")和年份区间(如 "2025/26")。
- 适用场景:
- 每日/每周生成持仓公司财报速览
- 事件驱动系统(监听财报发布日期自动触发)
- 对比多家公司财务表现的研究报告
- 不适用场景:需要实时 tick 数据或深度财务模型(这个 Skill 只做一级提取)。
完整 Skill 结构(SKILL.md 示例)
每个 Skill 本质上是一个可复用模块。我的习惯是:一个目录 + 一个 SKILL.md + 一个主函数脚本。目录结构如下:
financial-fetch-skill/
├── SKILL.md # 技能描述与触发配置
├── fetch_earnings.py # 核心逻辑(tavily搜索 + prompt提取)
├── config.yaml # API密钥、默认参数
└── requirements.txt # 依赖
SKILL.md 内容(可直接复制)
# SKILL:财报数据提取器
## 目标
根据公司名称和财年,从 TradingView 新闻中提取营收、净利润、EPS 等财务指标,返回结构化 JSON。
## 触发方式
```bash
python fetch_earnings.py --company "Imasen Elec" --year "2025/26"
输入参数
company: 字符串,公司全名或股票代码year: 字符串,财年标识,如 "2025/26"source: 可选,默认 "tradingview",预留扩展
输出格式
{
"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() 函数。
## 实际案例演示
下面我用 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(新手经常写)
"请从以下新闻中提取财报数据。"
结果:模型返回一段散文,没有数字,甚至可能说“未提供”。
好 Prompt(我的优化版)
你是一个金融数据提取器。给定一篇关于财报的新闻文本,你需要提取以下字段并返回 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. 完整提取函数
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. 主流程串联
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")
运行输出(示意):
{
"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:批量提取(多公司)
python batch_extract.py --companies "Toyota, Sony, Imasen" --year "2025/26"
在 search_financial_news 中循环调用即可,注意控制 TPM 限流。
变体2:集成到自动化报表系统
这个 Skill 可以嵌入 GitHub Actions 或 Airflow DAG:
# .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)。如果你有更好的优化思路,欢迎留言讨论。