Skill: zacbai/buffett-analysis (version 0.1.0)

--- name: buffett-analysis description: 巴菲特视角的上市公司基本面深度分析。当用户提到"分析一家公司"、"看看XX值不值得投资"、"XX的基本面怎么样"、"帮我研究一下XX"、个股分析、价值投资分析、公司估值、高管研究、管理层分析、公司战略、新闻采集、PR分析、业务出海、创新药等需求时使用。也支持行业分析——当用户提到"XX行业怎么样"、"帮我梳理一下XX赛道"、"XX产业链分析"、"行业一页纸"时使用。支持A股、港股、美股（NYSE/NASDAQ）。美股直接用 ticker（AAPL/TSLA/NVDA），A股用代码或中文名。自动获取财报、估值、行业数据、公司新闻、高管信息，按巴菲特投资框架出具完整分析报告。 --- # 巴菲特视角投资分析 ## 分析模式 根据用户需求自动判别分析模式： ### 模式A：个股基本面分析 - 触发词：分析XX公司、XX值不值得投资、XX基本面、研究XX - 流程：个股分析流程（Step 1-4） ### 模式B：行业一页纸 - 触发词：XX行业分析、XX赛道怎么样、XX产业链、行业一页纸 - 流程：行业分析流程（Step B1-B4） ### 模式C：专项研究 - 触发词：高管研究、新闻采集、战略分析、估值测算等 - 流程：可跳过财务数据采集，直接执行相关步骤 --- ## 分析方法论（通用） 所有分析都遵循这个方法论链条： ### 1. 问题定义 - 明确分析对象、范围、时间窗口 - 拆分为可验证的子命题 - 识别核心假设（需求驱动、供给约束、关键里程碑） ### 2. 证据搜集与溯源 - **优先来源**：公司年报/季报/招股书、政策原文、行业协会/统计局、权威机构报告 - **溯源**：找最早出处，标记是否存在信息偏差 - **质量评估**：可验证性、独立性、时效性、利益冲突 ### 3. 数据处理与分析 - 多源交叉验证，取可信、可溯源的信源 - 区分原始数据、计算数据、推理数据 - 定量计算 + 定性分析结合 ### 4. 论证检验 - 重构逻辑链：前提 → 推理 → 结论（每步标注证据） - 常见谬误自检：相关≠因果、以偏概全、诉诸权威 - 敏感性分析：核心假设变化对结论的影响 --- ## 个股分析框架（六大维度） ### 1. 🏭 行业定位与产业链 - 行业规模、增速、周期阶段 - 公司在产业链中的位置和话语权 - 市场空间（TAM/SAM/SOM） - 竞争格局（CR3/CR5、市占率变化） - 核心技术路线及公司技术代际 ### 2. 🏰 护城河分析 (Economic Moat) - **毛利率**：>40% 优秀，>60% 极强定价权 - **ROE**：连续>15% 是优质企业门槛，>20% 是护城河标志 - **ROIC**：>15% 说明资本配置效率高 - **技术壁垒**：专利、know-how、研发投入强度 - **资本壁垒**：进入门槛、固定资产投入 - **客户壁垒**：转换成本、认证周期 - **应收账款周转**：越快说明议价能力越强 ### 3. 📊 盈利质量 (Earnings Quality) - **经营现金流/净利润**：>80% 说明利润是"真金白银" - **自由现金流**：正且持续增长是好生意的标志 - **营收/利润增速**：关注稳定性而非单年爆发 - **扣非净利润 vs 净利润**：差距大说明非经常性损益多 - **资本开支强度**：Capex/营收，重投入期 vs 收获期 ### 4. 💰 财务健康 (Financial Health) - **资产负债率**：因行业而异，但过高(>60%)需警惕 - **流动比率/速动比率**：>2/>1 为安全 - **有息负债**：越少越好，巴菲特偏爱低负债公司 - **货币资金/短期借款**：>1 说明现金充裕 ### 5. 📐 估值合理性 (Valuation) - **PE-TTM**：与历史分位、同行对比 - **PB**：结合ROE看（高ROE高PB合理） - **EV/EBITDA**：剔除资本结构差异的估值指标 - **自由现金流收益率**：FCF/市值，>5% 有吸引力 - **股息率 + 回购收益率**（美股重点）：Total Shareholder Yield - **DCF 简化测算**：核心假设→目标价区间 ### 6. 👔 管理层与治理 (Management & Governance) - **高管背景**：CEO/董事长/核心高管的专业背景、行业经验 - **任职变动**：近期高管变动情况及可能原因 - **管理层持股**：利益绑定程度 - **战略方向**：管理层公开言论、战略规划、业务布局 ### 7. 📰 公开信息与事件驱动 (News & Catalysts) - **公司公告/PR**：重大公告、合作协议、审批进展 - **行业新闻**：行业政策、竞争格局变化 - **媒体报道**：正面/负面报道、市场情绪 - **事件催化**：近期可能影响股价的关键事件 --- ## 个股分析执行流程 ### Step 1a: 财务数据采集 **市场自动判别：** - 输入为英文 ticker（如 AAPL、TSLA、NVDA、GOOGL）或明确美股公司 → 美股路径 - 输入为中文名（贵州茅台）或 A 股代码（600519、000858）→ A 股路径 #### A股/港股路径 运行脚本（使用公司名或代码）： ```bash PATH="/home/node/.local/bin:$PATH" python3 scripts/fetch_company_data.py "贵州茅台" ``` 脚本输出 JSON 到 `/tmp/buffett_analysis_{code}.json`，包含： - 公司基本信息、行业分类 - 最新利润表、资产负债表、现金流量表 - 核心财务指标（ROE/ROIC/毛利率等，含多期对比） - 估值指标（PE/PB/PS/PCF） - 实时行情、市值 - 十大股东 - 同行业公司列表（用于对比） 如需同行对比数据，对2-3家可比公司额外运行： ```bash PATH="/home/node/.local/bin:$PATH" python3 scripts/fetch_company_data.py "五粮液" ``` #### 美股路径 运行美股采集脚本： ```bash python3 scripts/fetch_us_company_data.py AAPL ``` 脚本依次调用 us-market skill 采集 profile/financials/quote/analyst/dividends，输出到 `/tmp/buffett_analysis_{TICKER}.json`。 如需同行对比： ```bash python3 scripts/fetch_us_company_data.py MSFT ``` ### Step 1b: 行业与产业链数据采集 **这是新增的关键步骤——先看行业再看公司。** 1. **web_search** 搜索行业信息： - `"{行业名}" 市场规模 增速 2025 2026` - `"{行业名}" 产业链 竞争格局` - `"{行业名}" 技术路线 趋势` - `"{公司名}" 市占率 行业排名` 2. **web_fetch** 抓取关键行业报告/数据 3. **fintool MCP**（A股）获取行业数据： ``` fintool-plates.get_plate_list keyword="{行业名}" fintool-plates.get_plate_stocks plate_code="{板块代码}" ``` **整理要点：** - 行业规模及增速 - 公司在行业中的位置（市占率、排名） - 产业链上下游关系 - 竞争格局（CR3/CR5，主要竞争对手） - 核心技术路线及演进方向 ### Step 1c: 新闻/公开信息采集 #### A股路径 1. **web_search** 搜索公司最新新闻、PR稿件、公告： - 搜索 3-5 组不同关键词，覆盖不同角度 - 用 `freshness: "pm"` 限定近期新闻 2. **web_fetch** 对重要搜索结果抓取全文 3. **fintool-search**（MCP）获取财经新闻： ``` fintool-search.search_news keyword="{公司名}" count=20 ``` #### 美股路径 1. 用 us-market skill 获取新闻： ```bash python3 skills/us-market/scripts/us_market_query.py --type news --symbol AAPL ``` 2. **web_search** 补充搜索（英文关键词） 3. **web_fetch** 抓取关键报道全文 **信息整理要求：** - 按时间线整理关键事件 - 区分事实（公告/官方信息）和观点（分析师/媒体评论） - 标注信息来源和日期 - 识别信息之间的关联性 ### Step 1d: 高管与管理层研究 #### A股路径 1. **web_search** 搜索高管信息： - `"{公司名}" 高管 任命/变动/离职` - `"{高管姓名}" 背景/简历` 2. **web_fetch** 抓取关键人物报道 #### 美股路径 1. 用 us-market skill 获取内部交易数据： ```bash python3 skills/us-market/scripts/us_market_query.py --type insider --symbol AAPL ``` 2. **web_search** 搜索高管信息（英文） 3. **web_fetch** 抓取关键报道 #### 分析要点（通用） - 核心高管名单 - 教育背景、职业履历、专业领域 - 近期任职变动及原因 - 管理层持股变化（增持/减持信号） ### Step 2: 读取分析模板 ``` read references/analysis-template.md ``` ### Step 3: 撰写分析报告 结合采集数据 + 分析模板 + 以下原则撰写报告： **巴菲特语言风格：** - 用生活化比喻解释财务概念 - 适当引用巴菲特/芒格名言 - 给出明确观点，不做墙头草 - 永远提示风险 **分析深度要求：** - 不只列数字，要解读数字背后的商业逻辑 - **先看行业，再看公司**：行业景气度是个股表现的最大β - 结合产业链分析护城河的可持续性 - 横向对比（vs 同行）+ 纵向对比（vs 自身历史） - 供需框架分析：量×价，渗透率提升空间 - 最终给出清晰的投资价值判断 **输出格式：** - 飞书/群聊用 bullet points，不用 markdown 表格 - 先给结论（一句话总结），再展开分析 - 控制在合理篇幅（不要写论文） ### Step 4: 写入阿尔法工坊前端 每次完成基本面分析后，**必须**将报告数据写入前端展示： 1. 读取 `alpha-factor-lab/fundamental-reports.json` 2. 按以下 JSON 结构追加一条报告： ```json { "name": "公司名称", "code": "600519.SH 或 AAPL（美股直接用ticker）", "market": "A 或 US", "date": "2026-02-21", "rating": "推荐|强烈推荐|中性|回避|关注", "industry": { "name": "行业名称", "summary": "行业概况一句话", "position": "公司在产业链中的位置", "market_size": "行业市场规模", "growth": "行业增速", "competition": "竞争格局概述（CR3/市占率等）" }, "moat": { "score": 8, "summary": "护城河分析文字...", "metrics": { "毛利率": "91.3%", "ROE": "36.99%", ... } }, "earnings": { "score": 7, "summary": "盈利质量分析文字...", "metrics": { ... } }, "health": { "score": 9, "summary": "财务健康分析文字...", "metrics": { ... } }, "valuation": { "score": 6, "summary": "估值分析文字...", "metrics": { "PE-TTM": "20.66x", ... } }, "management": { "score": 7, "summary": "管理层与治理分析文字...", "key_people": ["姓名 - 职位 - 简要背景", ...], "recent_changes": ["变动描述1", ...] }, "catalysts": { "score": 7, "summary": "近期动态与催化分析文字...", "events": ["事件1（日期）", ...], "outlook": "前瞻判断文字..." }, "conclusion": "综合结论文字...", "risks": ["风险1", "风险2", ...] } ``` 3. 如果该公司已存在（按 code 匹配），则**覆盖更新**；否则追加 4. 写入后 commit 并 push 到 GitHub，确保阿尔法工坊在线页面同步更新 **阿尔法工坊地址：** https://finstep-ai.github.io/alpha-factor-lab/fundamental.html --- ## 行业一页纸执行流程 当用户要求分析一个行业时，走这个流程： ### Step B1: 行业数据采集 1. **web_search** 广泛搜索行业信息（至少10组关键词）： - `"{行业名}" 市场规模 2025 2026` - `"{行业名}" 产业链 全景图` - `"{行业名}" 竞争格局 市场份额` - `"{行业名}" 技术路线 趋势` - `"{行业名}" 政策 产业政策` - `"{行业名}" 龙头企业 排名` - `"{行业名}" 供需分析` - `"{行业名}" 投资逻辑 研报` - `"{行业名}" 国产替代 自主可控`（适用时） - `"{行业名}" 发展历程 历史` 2. **web_fetch** 抓取 5-10 篇核心报告/文章全文 3. **fintool MCP**（A股相关行业）： ``` fintool-plates.get_plate_list keyword="{行业名}" fintool-plates.get_plate_stocks plate_code="{板块代码}" fintool-company.get_company_info code="{龙头公司代码}" ``` 4. **us-market skill**（美股相关行业）： ```bash python3 skills/us-market/scripts/us_market_query.py --type profile --symbol {龙头ticker} python3 skills/us-market/scripts/us_market_query.py --type financials --symbol {龙头ticker} ``` ### Step B2: 读取行业分析模板 ``` read references/industry-template.md ``` ### Step B3: 撰写行业一页纸 按模板结构撰写，重点确保： **核心要求：** - **投资逻辑清晰**：开篇直奔核心——为什么这个行业值得关注？ - **产业链完整**：上中下游全覆盖，每个环节的竞争格局和趋势 - **数据扎实**：市场规模有量化测算，竞争格局有份额数据 - **技术前瞻**：不只看当下，还要看未来2-3年的技术演进 - **标的明确**：最后落到具体投资标的，有对比表格 **格式要求：** - 用清晰的标题层级结构 - 关键数据点标注来源 - 市场规模用表格展示 - 竞争格局用分梯队方式 - 投资标的用对比表格 ### Step B4: 写入阿尔法工坊前端 行业分析完成后，写入 `alpha-factor-lab/fundamental-reports.json`，格式如下： ```json { "name": "行业名称", "code": "INDUSTRY_{行业英文简称}", "market": "INDUSTRY", "date": "2026-02-22", "type": "industry", "rating": "推荐|强烈推荐|中性|回避|关注", "core_logic": { "summary": "核心投资逻辑概述...", "demand_drivers": ["需求驱动1", "需求驱动2"], "supply_dynamics": "供给端情况...", "outlook": "供需展望..." }, "industry_overview": { "definition": "行业定义...", "market_size": "市场规模...", "growth_rate": "增速...", "cycle_stage": "周期阶段...", "business_model": "商业模式概述...", "policy": "政策环境概述..." }, "supply_chain": { "upstream": { "summary": "上游分析...", "key_players": ["公司1", "公司2"] }, "midstream": { "summary": "中游分析...", "key_players": ["公司1", "公司2"] }, "downstream": { "summary": "下游分析...", "key_players": ["应用1", "应用2"] }, "tech_roadmap": "技术路线...", "moat": "行业护城河分析..." }, "market_sizing": { "current": "当前市场规模", "forecast": { "2025": "XX亿", "2026": "XX亿", "2030": "XX亿" }, "assumptions": ["假设1", "假设2"], "domestic_opportunity": "国产替代空间..." }, "competition": { "tier1": ["公司1 - 简述", "公司2 - 简述"], "tier2": ["公司1 - 简述", "公司2 - 简述"], "tier3": ["公司1 - 简述"] }, "top_picks": [ { "name": "公司名", "code": "代码", "segment": "所属环节", "thesis": "投资逻辑", "scarcity": true, "elasticity": "超额|平均|低于平均" } ], "risks": ["风险1", "风险2", "风险3"], "conclusion": "综合结论..." } ``` 写入后 commit 并 push。

path: references/analysis-template.md
content: # 个股分析报告模板

## 报告结构

### 1. 一句话结论

开篇直接给出投资价值判断，如：
> 贵州茅台是A股最强护城河企业之一，当前估值合理偏低，长期持有价值明确。

### 2. 🏭 行业定位与产业链分析

**先看行业，再看公司**——巴菲特说"在一条好的赛道上，平庸的马也能跑出好成绩"。

- **行业概况**：行业规模、增速、所处周期阶段
- **产业链位置**：公司处于上游/中游/下游？在价值链中的话语权
- **行业驱动因素**：
  - 需求侧：什么在驱动增长？（技术变革/政策/消费升级）
  - 供给侧：竞争格局如何？产能是否过剩/紧缺？
- **市场空间**：TAM/SAM/SOM，渗透率提升空间
- **竞争格局**：CR3/CR5集中度，公司市占率及变化趋势
- **技术路线**：当前主流技术 → 未来演进方向，公司技术代际

### 3. 🏰 护城河评估

从以下角度分析竞争优势是否持久：
- **品牌/定价权**：毛利率趋势、提价能力
- **规模效应**：行业地位、市占率、成本优势
- **转换成本**：客户黏性、应收账款周转
- **网络效应**：是否存在
- **技术壁垒**：专利、know-how、研发投入强度
- **资本壁垒**：进入门槛、固定资产投入规模
- **资本回报**：ROE、ROIC 连续多年表现

护城河评级：**宽/窄/无**

### 4. 📊 盈利能力解读

核心指标：
- **毛利率**：XX%（同行对比，趋势变化）
- **净利率**：XX%（注意非经常性损益影响）
- **ROE**：XX%（杜邦分解：利润率 × 周转率 × 杠杆）
- **ROIC**：XX%（与 WACC 对比）
- **营收增速**：近3年趋势，增长质量 vs 速度
- **净利增速**：近3年趋势，扣非 vs 归母

### 5. 💵 现金流质量（最重要！）

"利润是意见，现金是事实"。

- **经营现金流/净利润**：>100% 优秀，<70% 需警惕
- **自由现金流**：经营现金流 - 资本开支
- **自由现金流趋势**：是否持续为正且增长
- **收现比**：销售商品收到的现金/营收
- **资本开支强度**：Capex/营收，是否处于重投入期

### 6. 💰 财务安全性

- **资产负债率**：XX%（与行业均值对比）
- **流动比率/速动比率**：是否安全
- **有息负债**：总额、占比和趋势
- **货币资金/短期债务**：覆盖倍数
- **商誉占比**：>净资产20%需要警惕

### 7. 📐 估值分析

- **PE-TTM**：当前倍数（历史分位、同行对比）
- **PB**：PB-ROE 匹配度
- **EV/EBITDA**：剔除资本结构差异
- **自由现金流收益率**：FCF/市值
- **股息率 + 回购收益率**（美股）：Total Shareholder Yield
- **DCF 简化测算**：核心假设→目标价区间
- **与同行可比公司对比**

### 8. 👔 管理层与治理

- **核心管理层**：董事长/CEO/CFO 及关键业务负责人
  - 教育背景、职业履历、专业领域
- **近期变动**：谁走谁来？为什么？对战略的影响
- **管理层持股**：持股比例及增减持信号
- **战略方向**：管理层公开言论、战略规划
- **治理风险**：家族/职业经理人、董事会独立性、历史争议

### 9. 📰 近期动态与事件催化

- **重大公告/PR**：按时间线列出，每个事件评估影响
- **行业政策**：相关监管变化
- **业务进展**：新产品/新市场/出海/研发管线
- **市场情绪**：分析师观点、机构调研
- **前瞻判断**：
  - 关键里程碑时间点
  - 乐观/悲观情景分析
  - 催化剂清单

### 10. 🚩 风险提示

- 行业风险（周期、技术路线、政策）
- 公司特有风险（竞争、管理层、客户集中度）
- 估值风险
- 宏观/地缘风险

### 11. 🎯 总结评分

用简单的打分体系：
- 行业景气度：X/5
- 护城河：X/5
- 盈利质量：X/5
- 财务健康：X/5
- 估值合理性：X/5
- 管理层质量：X/5
- 近期催化/风险：X/5
- **综合评分：X/5**

最后一句引用巴菲特名言收尾。

## 数据与方法论规范

### 证据追溯
- 优先来源：公司年报/季报、交易所公告、行业协会、权威机构报告
- 多源交叉验证（至少2个独立来源确认关键数据）
- 区分事实（公告/官方数据）和观点（分析师/媒体评论）

### 量化分析
- 横向对比：vs 同行 2-3 家可比公司
- 纵向对比：vs 自身历史 3-5 年
- 供需框架：量×价分析
- 敏感性分析：关键假设变化对估值的影响

### 数字解读规则
- 金额：>1亿用"亿"，>1万用"万"
- 百分比保留1-2位小数
- 同比标注"+X%"或"-X%"
- 异常值（ROE>50%或<0）要特别解释原因

### 格式要求
- 飞书/群聊用 bullet 列表，不用表格
- 阿尔法工坊 JSON 输出可用结构化数据
- 先给结论，再展开分析
- 每个观点有数据支撑

### 风格要求
- 像跟懂行的朋友聊天，有深度但不学究
- 巴菲特/芒格名言穿插（不硬凑）
- 给明确结论，不骑墙
- 数据驱动


path: references/industry-template.md
content: # 行业一页纸模板

## 报告结构

### 1. 核心投资逻辑

开篇用1-2段话概括这个行业最核心的投资逻辑：
- 需求侧驱动因素（2-3个关键点，每个展开说明）
- 供给侧格局（产能、扩产节奏、结构性变化）
- 供需结论：是否存在明确的供需缺口/顺风？持续多久？

### 2. 行业全景分析

#### 2.1 行业定义与存在价值
- 行业属于什么大类？市场规模占比
- 核心产品/服务类别（分类清晰）
- 行业解决了什么核心痛点？为什么不可替代？
- 重要时间节点（过去的里程碑 + 未来的关键窗口期）

#### 2.2 行业发展历程
- 按阶段梳理（探索期→成长期→成熟期→变革期）
- 标注关键拐点及其原因
- 中国市场的特殊发展路径

#### 2.3 商业模式解析
- 主流商业模式（IDM/Fabless/平台型等）
- 利润核心驱动因素（技术溢价/规模效应/周期定价/网络效应）
- 成本结构拆解（固定 vs 可变，哪个环节最吃利润）
- 价值链分配：哪个环节赚最多钱？为什么？

#### 2.4 政策环境分析
- 国家战略/产业政策支持
- 监管环境（利好 vs 约束）
- 国际贸易/地缘政治影响
- 政策总结论：对本土企业是利还是弊？

### 3. 产业链深度解析

#### 3.1 产业链图谱
- 上游 → 中游 → 下游的完整链条
- 每个环节的核心玩家
- 产品/价值流向

#### 3.2 上游分析
- 竞争格局（国际 vs 国内）
- 国产化率和替代空间
- 核心受益逻辑

#### 3.3 中游分析
- 各子环节的格局和趋势
- 哪个环节壁垒最高？弹性最大？
- 核心结论

#### 3.4 下游分析
- 应用市场结构及变化趋势
- 需求驱动力从哪来？正在往哪转移？
- 最强劲的增长点在哪？

#### 3.5 核心技术路线
- 当前主流技术（参数、指标、代际）
- 未来演进趋势
- 颠覆性技术及产业化时间窗口
- 技术变化对竞争格局的影响

#### 3.6 行业护城河分析
- 技术壁垒
- 资本壁垒
- 规模壁垒
- 客户/认证壁垒
- 政策/资质壁垒

### 4. 市场空间测算

#### 4.1 供需现状与核心假设
- 需求端量化（增速、驱动因素）
- 供给端量化（产能、扩产节奏）
- 核心假设明确列出（可追溯、可验证）

#### 4.2 市场规模测算
- 表格形式：当前 → 未来3-5年的市场规模预测
- 分细分市场/产品线的拆解
- 国产替代潜在空间
- 测算说明（数据来源、关键假设、敏感性）

### 5. 市场竞争格局

#### 5.1 核心玩家梯队
- 第一梯队：全球/全国龙头
- 第二梯队：区域性强者/追赶者
- 第三梯队：利基市场/新进入者
- 每个梯队的特征和代表公司

#### 5.2 核心对比分析
- 市场份额图（如有数据）
- 对比表格：技术优势、市场地位、核心评价
- 竞争格局的变化趋势

### 6. 重点投资标的分析

每个标的：
- **业务布局**：主营业务、技术壁垒、客户结构
- **投资逻辑**：为什么值得关注？差异化在哪？催化剂是什么？

#### 投资价值综合对比表
表格形式：环节 | 公司 | 代码 | 稀缺性 | 受益逻辑 | 弹性评级

### 7. 风险提示
- 行业周期风险
- 技术路线风险
- 政策/地缘风险
- 估值风险
- 竞争风险

## 数据与方法论规范

### 证据追溯
- 优先来源：公司年报/季报、行业协会/统计局、权威机构报告
- 多源交叉验证
- 标注数据来源和时效性

### 分析方法
- 定量为主：市场规模、增速、份额、毛利率等用具体数字
- 供需框架：量×价分析，渗透率测算
- 情景分析：乐观/基准/悲观假设

### 格式要求
- 数据表格用 markdown table（前端支持）
- 核心数据标注来源
- 金额统一为亿美元或亿元人民币
- 增速/份额用百分比，保留1位小数


path: scripts/fetch_company_data.py
content: #!/usr/bin/env python3
"""
巴菲特基本面分析 - 数据采集脚本
================================
自动获取一家上市公司的全面财务数据，输出结构化JSON供分析使用。

用法：
    python3 fetch_company_data.py "贵州茅台"
    python3 fetch_company_data.py "600519"
    python3 fetch_company_data.py "比亚迪" --peers "长城汽车,长安汽车"
"""

import json
import os
import subprocess
import sys
import time
from datetime import datetime

ENV = os.environ.copy()
ENV["PATH"] = "/home/node/.local/bin:" + ENV.get("PATH", "")

def mcporter(tool, **kwargs):
    """调用 mcporter MCP 工具"""
    args = " ".join(f"{k}={v}" for k, v in kwargs.items())
    cmd = f"mcporter call {tool} {args}"
    try:
        r = subprocess.run(cmd, shell=True, capture_output=True, text=True, env=ENV, timeout=60)
        if r.stdout.strip():
            return json.loads(r.stdout)
    except (json.JSONDecodeError, subprocess.TimeoutExpired) as e:
        pass
    return None


def mcporter_to_file(tool, out_path, **kwargs):
    """大数据量 API 先写文件再解析"""
    args = " ".join(f"{k}={v}" for k, v in kwargs.items())
    cmd = f"mcporter call {tool} {args}"
    try:
        with open(out_path, "w") as f:
            subprocess.run(cmd, shell=True, stdout=f, stderr=subprocess.DEVNULL, env=ENV, timeout=60)
        if os.path.getsize(out_path) > 2:
            with open(out_path) as f:
                return json.load(f)
    except (json.JSONDecodeError, subprocess.TimeoutExpired, OSError):
        pass
    return None


def safe_first(data):
    """安全取第一个元素"""
    if isinstance(data, list) and data:
        return data[0]
    if isinstance(data, dict):
        return data
    return {}


def fetch_company_data(keyword):
    """获取公司全面数据"""
    result = {
        "keyword": keyword,
        "fetch_time": datetime.now().strftime("%Y-%m-%d %H:%M"),
        "errors": []
    }

    # ━━━ 1. 公司基本信息 ━━━
    print(f"[1/10] 公司基本信息...", flush=True)
    info = mcporter("fintool-company.get_company_base_info", keyword=keyword)
    if info:
        result["company_info"] = info
        result["name"] = info.get("security_name", keyword)
    else:
        result["company_info"] = {}
        result["name"] = keyword
        result["errors"].append("公司基本信息获取失败")

    # ━━━ 2. 行业分类 ━━━
    print(f"[2/10] 行业分类...", flush=True)
    industry = mcporter("fintool-company.get_stock_industry_sws", keyword=keyword)
    result["industry"] = safe_first(industry) if industry else {}
    # 从行业数据中获取证券代码
    if result["industry"].get("security_code"):
        result["code"] = result["industry"]["security_code"]
    time.sleep(0.2)

    # ━━━ 3. 所属板块 ━━━
    print(f"[3/10] 所属板块...", flush=True)
    plates = mcporter("fintool-plates.get_stock_plate", keyword=keyword)
    if isinstance(plates, list):
        result["plates"] = [{"name": p.get("plate_name", ""), "profile": p.get("stock_profiles", "")[:200]} for p in plates[:5]]
    else:
        result["plates"] = []

    # ━━━ 4. 核心财务指标（多期） ━━━
    print(f"[4/10] 核心财务指标...", flush=True)
    metrics = mcporter_to_file("fintool-company.get_financial_analytics_metric", "/tmp/fam_raw.json", keyword=keyword)
    if isinstance(metrics, list):
        result["financial_metrics"] = metrics[:4]  # 最近4期
    else:
        result["financial_metrics"] = []
        result["errors"].append("财务指标获取失败")
    time.sleep(0.2)

    # ━━━ 5. 利润表（多期） ━━━
    print(f"[5/10] 利润表...", flush=True)
    income_statements = []
    for end_date in ["2025-12-31", "2025-09-30", "2025-06-30", "2024-12-31", "2024-06-30", "2023-12-31"]:
        inc = mcporter("fintool-company.get_income_statement", keyword=keyword, end_date=end_date)
        if inc:
            item = safe_first(inc)
            if item and item.get("end_date"):
                existing_dates = [x.get("end_date") for x in income_statements]
                if item["end_date"] not in existing_dates:
                    income_statements.append(item)
        time.sleep(0.15)
    result["income_statements"] = income_statements

    # ━━━ 6. 资产负债表 ━━━
    print(f"[6/10] 资产负债表...", flush=True)
    balance_sheets = []
    for end_date in ["2025-12-31", "2025-09-30", "2024-12-31", "2023-12-31"]:
        bs = mcporter("fintool-company.get_balance_sheet", keyword=keyword, end_date=end_date)
        if bs:
            item = safe_first(bs)
            if item and item.get("end_date"):
                existing_dates = [x.get("end_date") for x in balance_sheets]
                if item["end_date"] not in existing_dates:
                    balance_sheets.append(item)
        time.sleep(0.15)
    result["balance_sheets"] = balance_sheets

    # ━━━ 7. 现金流量表 ━━━
    print(f"[7/10] 现金流量表...", flush=True)
    cash_flows = []
    for end_date in ["2025-12-31", "2025-09-30", "2024-12-31", "2024-06-30", "2023-12-31"]:
        cf = mcporter("fintool-company.get_cash_flow", keyword=keyword, end_date=end_date)
        if cf:
            item = safe_first(cf)
            if item and item.get("end_date"):
                existing_dates = [x.get("end_date") for x in cash_flows]
                if item["end_date"] not in existing_dates:
                    cash_flows.append(item)
        time.sleep(0.15)
    result["cash_flows"] = cash_flows

    # ━━━ 8. 估值指标 ━━━
    print(f"[8/10] 估值指标...", flush=True)
    val = mcporter("fintool-company.get_valuation_metrics_daily", keyword=keyword, end_date="2026-02-17")
    result["valuation"] = safe_first(val) if val else {}
    time.sleep(0.2)

    # ━━━ 9. 实时行情 ━━━
    print(f"[9/10] 实时行情...", flush=True)
    snap = mcporter("fintool-quote.get_snapshot", keyword=keyword)
    if snap:
        result["snapshot"] = snap
    else:
        result["snapshot"] = {}
    time.sleep(0.2)

    # ━━━ 10. 股东信息 ━━━
    print(f"[10/10] 股东信息...", flush=True)
    holders = mcporter("fintool-company.get_share_holder_info", keyword=keyword)
    if isinstance(holders, list):
        result["top_holders"] = holders[:10]
    else:
        result["top_holders"] = []

    # ━━━ 同行业公司列表 ━━━
    if result.get("industry", {}).get("second_industry_name"):
        ind_name = result["industry"]["second_industry_name"].rstrip("ⅡⅢⅠ").strip()
        print(f"[+] 同行业板块: {ind_name}", flush=True)
        peers_data = mcporter("fintool-plates.get_plate_stocks", keyword=ind_name)
        if isinstance(peers_data, dict) and "stocks" in peers_data:
            stocks = peers_data["stocks"]
            # 取前10，按市值排序（如果有）
            result["industry_peers"] = [
                {
                    "code": s.get("security_code"),
                    "name": s.get("security_name", "").strip(),
                    "price": s.get("last_price"),
                    "change": s.get("price_change_rate"),
                    "market_cap": s.get("market_value"),
                    "pe": s.get("pe_ratio"),
                }
                for s in stocks[:15]
            ]
        else:
            result["industry_peers"] = []

    return result


def main():
    if len(sys.argv) < 2:
        print("用法: python3 fetch_company_data.py <公司名或代码> [--peers 可比公司1,可比公司2]")
        sys.exit(1)

    keyword = sys.argv[1]
    print(f"━━━ 采集 {keyword} 财务数据 ━━━", flush=True)

    data = fetch_company_data(keyword)

    # 确定输出文件名
    code = data.get("code", data.get("name", keyword))
    name = data.get("name", keyword)
    # 安全文件名
    safe_name = code.replace("/", "_").replace(" ", "_")
    out_path = f"/tmp/buffett_analysis_{safe_name}.json"

    with open(out_path, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False, default=str)

    print(f"\n━━━ 完成 ━━━")
    print(f"公司: {name} ({code})")
    print(f"利润表: {len(data['income_statements'])} 期")
    print(f"资产负债表: {len(data['balance_sheets'])} 期")
    print(f"现金流量表: {len(data['cash_flows'])} 期")
    print(f"财务指标: {len(data['financial_metrics'])} 期")
    print(f"同行业: {len(data.get('industry_peers', []))} 家")
    if data["errors"]:
        print(f"⚠️ 错误: {data['errors']}")
    print(f"输出: {out_path}")


if __name__ == "__main__":
    main()


path: scripts/fetch_us_company_data.py
content: #!/usr/bin/env python3
"""
美股公司基本面数据采集脚本
==========================
调用 us-market skill 统一入口，批量采集美股公司数据用于巴菲特分析。

用法：
    python3 fetch_us_company_data.py AAPL
    python3 fetch_us_company_data.py NVDA
"""

import json
import os
import subprocess
import sys
import time
from datetime import datetime

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
US_MARKET_SCRIPT = os.path.join(SCRIPT_DIR, '..', '..', 'us-market', 'scripts', 'us_market_query.py')


def run_query(query_type, symbol, **extra_args):
    """调用 us_market_query.py 并读取输出"""
    cmd = [sys.executable, US_MARKET_SCRIPT, '--type', query_type, '--symbol', symbol]
    for k, v in extra_args.items():
        cmd.extend([f'--{k}', str(v)])
    
    try:
        r = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    except subprocess.TimeoutExpired:
        return None
    
    # 读取输出文件
    safe_sym = symbol.upper().replace('^', 'IDX_').replace('/', '_')
    out_path = f"/tmp/us_market_{query_type}_{safe_sym}.json"
    if os.path.exists(out_path):
        with open(out_path, encoding='utf-8') as f:
            data = json.load(f)
            if 'error' not in data:
                return data
    return None


def fetch_us_company(ticker):
    """采集美股公司全面数据"""
    ticker = ticker.upper()
    result = {
        'symbol': ticker,
        'market': 'US',
        'fetch_time': datetime.now().strftime('%Y-%m-%d %H:%M'),
        'errors': []
    }

    # ━━━ 1. 公司概况 ━━━
    print(f"[1/7] 公司概况...", flush=True)
    profile = run_query('profile', ticker)
    if profile:
        result['company_info'] = profile
        result['name'] = profile.get('name', ticker)
    else:
        result['company_info'] = {}
        result['name'] = ticker
        result['errors'].append('公司概况获取失败')

    # ━━━ 2. 实时行情 ━━━
    print(f"[2/7] 实时行情...", flush=True)
    quote = run_query('quote', ticker)
    if quote:
        result['snapshot'] = quote
    else:
        result['snapshot'] = {}
        result['errors'].append('行情获取失败')
    time.sleep(0.3)

    # ━━━ 3. 利润表 ━━━
    print(f"[3/7] 利润表...", flush=True)
    income = run_query('financials', ticker, statement='income')
    if income:
        result['income_statements'] = income.get('data', {})
        result['income_periods'] = income.get('periods', [])
    else:
        result['income_statements'] = {}
        result['income_periods'] = []
        result['errors'].append('利润表获取失败')
    time.sleep(0.3)

    # ━━━ 4. 资产负债表 ━━━
    print(f"[4/7] 资产负债表...", flush=True)
    balance = run_query('financials', ticker, statement='balance')
    if balance:
        result['balance_sheets'] = balance.get('data', {})
        result['balance_periods'] = balance.get('periods', [])
    else:
        result['balance_sheets'] = {}
        result['balance_periods'] = []
        result['errors'].append('资产负债表获取失败')
    time.sleep(0.3)

    # ━━━ 5. 现金流量表 ━━━
    print(f"[5/7] 现金流量表...", flush=True)
    cashflow = run_query('financials', ticker, statement='cashflow')
    if cashflow:
        result['cash_flows'] = cashflow.get('data', {})
        result['cashflow_periods'] = cashflow.get('periods', [])
    else:
        result['cash_flows'] = {}
        result['cashflow_periods'] = []
        result['errors'].append('现金流量表获取失败')
    time.sleep(0.3)

    # ━━━ 6. 分析师评级 ━━━
    print(f"[6/7] 分析师评级...", flush=True)
    analyst = run_query('analyst', ticker)
    if analyst:
        result['analyst'] = analyst
    else:
        result['analyst'] = {}

    # ━━━ 7. 分红记录 ━━━
    print(f"[7/7] 分红记录...", flush=True)
    dividends = run_query('dividends', ticker)
    if dividends:
        result['dividends'] = dividends.get('dividends', [])
    else:
        result['dividends'] = []

    return result


def main():
    if len(sys.argv) < 2:
        print("用法: python3 fetch_us_company_data.py <美股ticker>")
        print("示例: python3 fetch_us_company_data.py AAPL")
        sys.exit(1)

    ticker = sys.argv[1].upper()
    print(f"━━━ 采集 {ticker} 基本面数据（美股）━━━", flush=True)

    data = fetch_us_company(ticker)

    out_path = f"/tmp/buffett_analysis_{ticker}.json"
    with open(out_path, 'w', encoding='utf-8') as f:
        json.dump(data, f, indent=2, ensure_ascii=False, default=str)

    print(f"\n━━━ 完成 ━━━")
    print(f"公司: {data['name']} ({ticker})")
    print(f"利润表: {len(data.get('income_periods', []))} 期")
    print(f"资产负债表: {len(data.get('balance_periods', []))} 期")
    print(f"现金流量表: {len(data.get('cashflow_periods', []))} 期")
    if data['errors']:
        print(f"⚠️ 错误: {data['errors']}")
    print(f"输出: {out_path}")


if __name__ == '__main__':
    main()


Security scan verdicts — ClawScan: suspicious | static analysis:  | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)