| name | comps-analysis |
| description | 可比公司分析(Comps / Comparable Company Analysis)工具。当用户需要"做可比公司分析"、"可比公司估值"、"同业对比"、"PE/PB对比"、"估值倍数分析"、"做comps"、"可比公司表格"时触发。
支持 A 股、港股、美股可比公司分析,输出专业级 Excel 表格,包含经营指标、估值倍数、统计分位(最大/75分位/中位数/25分位/最小)。
使用 Python/openpyxl 生成独立 .xlsx 文件。
优先使用 AKShare、Tushare、Wind 等国内数据接口获取 A 股和港股数据。参考 china-market-data skill 获取标准化数据获取代码模板。
不适用场景:非上市公司(无公开可比 peers)、Pre-revenue 初创公司、极端困境企业。
|
可比公司分析(Comparable Company Analysis)
数据来源与获取
数据获取优先级(按可靠性排序):
- 用户直接提供 - 如果用户给了数据文件(CSV/Excel)或粘贴了数据,优先使用
- Web Search 搜索 - 用搜索引擎获取最新财务数据(东方财富、同花顺、Yahoo Finance、公司年报等)
- 本地数据文件 - 读取用户工作目录下的数据文件
常用数据源:
- A股:东方财富网、同花顺、巨潮资讯网、交易所公告
- 港股:港交所披露易、阿斯达克
- 美股:SEC EDGAR (仅限美股标的)、AKShare/Tushare (覆盖美股中概)、公司 Investor Relations
数据质量要求:
- 时间口径一致(全部用 LTM/TTM 或同一个财报期)
- 币种统一(A股用人民币,港股可用港币或折算人民币,美股用美元)
- 标注数据来源和获取日期
核心方法论
"先搭结构,再让数据说话"
从表头设计开始强制思考分析重点,填入干净数据,构建透明公式,让统计结果自然浮现。一个好的 comps 表格应该让没参与制作的人一眼看懂。
⚠️ 关键原则:公式而非硬编码 + 分步验证
技术实现:
- 生成独立 .xlsx 文件:使用 Python + openpyxl
- 所有衍生值(利润率、估值倍数、统计量)必须是 Excel 公式引用输入单元格 —— 绝不粘贴预计算数值
- 唯一可硬编码的是原始输入数据(营收、EBITDA、股价等)—— 每个硬编码值需标注来源
- 模型必须在输入变动时自动更新。硬编码的利润率是埋下的沉默 bug
分步与用户确认:
- 搭建完结构后 → 先展示表头布局给用户确认
- 填入原始数据后 → 展示输入区块,确认数据源/期间后再构建公式
- 构建完经营指标公式后 → 展示计算结果, sanity check 后再进入估值
- 构建完估值倍数后 → 展示倍数,确认合理后再加统计量
- 不要一次性从头到尾做完再呈现 —— 分阶段确认,尽早发现错误
Section 1: 文档结构与表头
表头区块(第 1-3 行)
第 1 行: 【分析标题】- 可比公司分析
第 2 行: 【公司列表及代码】• 公司1 (代码1) • 公司2 (代码2) • 公司3 (代码3)
第 3 行: 截至 【期间】 | 除每股数据和比率外,单位为 【人民币百万元】
为什么重要: 打开文件的人立即知道在看什么、什么时候做的、如何理解数字。
视觉规范(建议默认值,用户偏好和上传模板永远优先)
字体与排版:
- 字体:Times New Roman(专业、可读、行业标准)
- 字号:数据 11pt,表头 12pt
- 加粗:章节标题、公司名称、统计标签
配色方案 — 专业蓝灰色调(极简原则):
- 章节标题(如"经营指标与财务数据"):深蓝背景
#1F4E79 或藏青 #17365D,白色加粗字,整行填充
- 列标题(如"公司"、"营收"、"利润率"):浅蓝背景
#D9E1F2,黑色加粗字,居中
- 数据行:白色背景,黑色字(公式);蓝色字(硬编码输入)
- 统计行(最大、75分位等):浅灰背景
#F2F2F2,黑色字,标签左对齐
- 整个调色板就这些:深蓝 + 浅蓝 + 浅灰 + 白色。除非用户模板另有要求,不要引入绿/橙/红等多色。
格式惯例:
- 百分比:1 位小数(12.3%)
- 倍数:1 位小数(13.5x)
- 金额:无小数,千分位分隔符(69,632)
- 边框:无边框(干净、极简外观)
- 对齐:所有指标居中,打造统一整洁观感
- 列宽:统一/等宽;行高:一致(数据行约 20-25pt)
Section 2: 经营指标与财务数据
核心列(必含)
- 公司 - 名称,格式统一
- 营收 - 规模指标(可用 LTM、季度或年度,视场景而定)
- 营收增速 - 同比增速
- 毛利润 - 营收减营业成本
- 毛利率 - 毛利润/营收(基础盈利能力)
- EBITDA - 息税折旧摊销前利润
- EBITDA 利润率 - EBITDA/营收(运营效率)
可选补充(根据行业/目的选择)
- 季度 vs LTM - 如果季节性重要,两者都列
- 自由现金流 - 资本密集型或 SaaS 企业
- FCF 利润率 - FCF/营收(现金创造效率)
- 净利润 - 成熟盈利公司
- 经营利润 - D&A 差异大的企业
- 资本开支指标 - 重资产行业
- Rule of 40 - SaaS 专用(增速% + 利润率%)
- FCF 转化率 - 盈利质量分析(进阶)
公式示例(以第 7 行为例)
// 核心比率 — 始终计算
毛利率 (F7): =E7/C7
EBITDA 利润率 (H7): =G7/C7
// 可选比率 — 相关时纳入
FCF 利润率: =[FCF]/[营收]
净利润率: =[净利润]/[营收]
Rule of 40: =[增速%]+[FCF 利润率%]
黄金法则: 每个比率应该是【某指标】/【营收】或【某指标】/【本表某指标】。保持简单。
统计区块(公司数据下方)
关键:为所有可比指标(比率、利润率、增速、倍数)添加统计公式。
【空一行作为视觉分隔】
- 最大值: =MAX(B7:B9)
- 75 分位: =QUARTILE(B7:B9,3)
- 中位数: =MEDIAN(B7:B9)
- 25 分位: =QUARTILE(B7:B9,1)
- 最小值: =MIN(B7:B9)
需要统计的列(可比指标):
- 营收增速%、毛利率%、EBITDA 利润率%、EPS
- EV/营收、EV/EBITDA、P/E、股息率%、Beta
不需要统计的列(规模指标):
- 营收、EBITDA、净利润(绝对规模因公司体量而异)
- 市值、企业价值(不同体量公司不具可比性)
注意: 公司数据和统计行之间空一行。不要加"行业统计"或"估值统计"标题行。
为什么用四分位: 展示分布,而非只有平均值。75 分位倍数告诉你"溢价"公司交易在什么水平。
Section 3: 估值倍数与投资指标
核心估值列(必含)
- 公司 - 与经营部分顺序一致
- 市值 - 当前市场估值
- 企业价值 - 市值 ± 净债务/现金
- EV/营收 - 市场愿意为每 1 元营收付多少
- EV/EBITDA - 市场愿意为每 1 元盈利付多少
- P/E 比率 - 价格相对净利润
可选估值指标(视场景而定)
- FCF 收益率 - FCF/市值(现金流导向分析)
- PEG 比率 - P/E/增速(成长股)
- 市净率 - 市值/账面价值(重资产企业)
- ROE/ROA - 回报指标(盈利能力对比)
- 营收/EBITDA CAGR - 历史增速(趋势分析)
- 资产周转率 - 营收/总资产(运营效率)
- 负债权益比 - 杠杆(资本结构分析)
公式示例
// 核心倍数 — 始终纳入
EV/营收: =[企业价值]/[LTM 营收]
EV/EBITDA: =[企业价值]/[LTM EBITDA]
P/E: =[市值]/[净利润]
// 可选倍数 — 有数据时纳入
FCF 收益率: =[LTM FCF]/[市值]
PEG: =[P/E]/[增速%]
交叉引用规则
关键: 估值倍数必须引用经营指标区块。同一原始数据不要输入两次。如果营收在 C7,EV/营收公式应该引用 C7。
统计区块
与经营部分相同结构:最大、75 分位、中位数、25 分位、最小值。公司数据和统计行之间空一行,不要加"估值统计"标题行。
Section 4: 注释与方法论文档
必含要素
数据来源与质量:
- 数据来自哪里?(东方财富、同花顺、年报、招股书)
- 覆盖什么期间?(2024 年报,经审计数据)
- 如何验证?(与年报交叉核对)
- 优先使用权威数据源(交易所公告、公司年报),其次用财经网站
关键定义:
- EBITDA 计算方法(毛利润 + D&A,或经营利润 + D&A)
- 自由现金流公式(经营现金流 - 资本开支)
- 特殊指标解释(Rule of 40、FCF 转化率)
- 时间口径定义(LTM、CAGR 计算期)
估值方法论:
- 企业价值如何计算?(市值 + 净债务)
- 使用什么增速?(历史 CAGR、前瞻预期)
- 做了哪些调整?(剔除非经常性项目、归一化利润率)
分析框架:
- 投资主题是什么?(云/SaaS 效率)
- 哪些指标最重要?(现金创造、资本效率)
- 读者应如何理解统计结果?(四分位提供上下文)
Section 5: 如何选择指标(决策框架)
从"我要回答什么问题"出发
"哪家公司被低估了?"
→ 重点:EV/营收、EV/EBITDA、P/E、市值
→ 跳过:运营细节、增速指标
"哪家公司效率最高?"
→ 重点:毛利率、EBITDA 利润率、FCF 利润率、资产周转率
→ 跳过:规模指标、绝对金额
"哪家公司增长最快?"
→ 重点:营收增速%、EBITDA CAGR、用户/客户增速
→ 跳过:利润率、杠杆比率
"哪家现金创造能力最强?"
→ 重点:FCF、FCF 利润率、FCF 转化率、资本开支强度
→ 跳过:EBITDA、P/E
行业特定指标选择
软件/SaaS:
必含:营收增速、毛利率、Rule of 40
可选:ARR、净收入留存率、CAC 回收期
跳过:资产周转率、库存指标
制造/工业:
必含:EBITDA 利润率、资产周转率、资本开支/营收
可选:ROA、库存周转、在手订单
跳过:Rule of 40、SaaS 指标
金融服务:
必含:ROE、ROA、效率比、P/E
可选:净息差、贷款损失准备金
跳过:毛利率、EBITDA(对银行意义有限)
零售/电商:
必含:营收增速、毛利率、库存周转
可选:同店销售、获客成本
跳过:重研发或资本开支指标
"5-10 法则"
5 个经营指标 - 营收、增速、2-3 个利润率/效率指标
5 个估值指标 - 市值、EV、3 个倍数
= 共 10 列 — 足够讲故事,不会信息过载
如果超过 15 个指标,大概率在引入噪音。无情删减。
Section 6: 最佳实践与质量检查
开始之前
- 定义可比公司群 - 公司必须真正可比(相似商业模式、规模、地域)
- 选择正确期间 - LTM 平滑季节性;季度展示趋势
- ** upfront 统一单位** - 百万 vs 十亿的决策影响一切
- 标注数据来源 - 知道每个数字来自哪里
构建过程中
-
先输入所有原始数据 - 蓝色字输入完成后再写公式
-
为所有硬编码输入添加单元格注释 - 右键单元格 → 插入注释 → 记录来源或假设
有来源的数据,精确标注出处:
- 例:"东方财富网 - 贵州茅台 2024 年报,2025-04-02 获取"
- 例:"2024 年年报第 42 页,'营业总收入'科目"
- 例:"同花顺 iFinD,2025-06-10"
- 尽可能加超链接:右键单元格 → 链接 → 粘贴年报或数据源 URL
假设性数据,解释推理:
- 例:"假设 EBITDA 利润率 15%,基于同业中位数,公司未披露"
- 例:"企业价值按市值 + 50 亿净债务估算(来自 Q3 资产负债表,Q4 尚未发布)"
- 例:"前瞻 P/E 基于一致预期 EPS 3.45 元(12 家分析师预期中位数)"
为什么重要:实现审计追踪、数据验证、假设透明、未来更新
-
逐行构建公式 - 每算完一行测试通过再下一行
-
表头用绝对引用 - $C$6 锁定表头行
-
格式统一 - 百分比就用百分比格式,不用小数
-
添加条件格式 - 自动高亮异常值
合理性检查
- 利润率检验:毛利率 > EBITDA 利润率 > 净利润率(按定义永远成立)
- 倍数合理性:
- EV/营收:通常 0.5-20x(因行业差异大)
- EV/EBITDA:通常 8-25x(跨行业相对一致)
- P/E:通常 10-50x(取决于增速)
- 增速-倍数相关性:高增速通常对应高倍数
- 规模-效率权衡:大公司通常利润率更好(规模效应)
常见错误
❌ 公式中混用市值和企业价值
❌ 分子分母使用不同期间(LTM vs 季度)
❌ 硬编码数字进公式而非单元格引用
❌ 硬编码输入没有单元格注释说明来源或假设
❌ 有 URL 可用时没加超链接到年报或数据源
❌ 指标过多且无明确目的
❌ 纳入非可比公司(商业模式差异大)
❌ 使用过期数据未披露
❌ 百分比算平均值有误(应该用中位数)
Section 7: Python/openpyxl 实现指南
基础结构代码
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border
from openpyxl.utils import get_column_letter
wb = Workbook()
ws = wb.active
ws.title = "可比公司分析"
ws['A1'] = "科技行业 - 可比公司分析"
ws['A2'] = "微软 (MSFT) • 谷歌 (GOOGL) • 亚马逊 (AMZN)"
ws['A3'] = "截至 2024 年 Q4 | 除每股数据和比率外,单位为 百万美元"
ws.merge_cells('A1:H1')
ws.merge_cells('A2:H2')
ws.merge_cells('A3:H3')
dark_blue = PatternFill(start_color="1F4E79", end_color="1F4E79", fill_type="solid")
white_font = Font(color="FFFFFF", bold=True, size=12)
ws['A1'].fill = dark_blue
ws['A1'].font = white_font
ws['A1'].alignment = Alignment(horizontal='center')
ws['A5'] = "经营指标与财务数据"
ws.merge_cells('A5:H5')
ws['A5'].fill = dark_blue
ws['A5'].font = white_font
ws['A5'].alignment = Alignment(horizontal='center')
headers = ["公司", "营收\n(LTM)", "增速\n(YoY)", "毛利润", "毛利率", "EBITDA", "EBITDA\n利润率"]
light_blue = PatternFill(start_color="D9E1F2", end_color="D9E1F2", fill_type="solid")
bold_font = Font(bold=True)
for col, header in enumerate(headers, 1):
cell = ws.cell(row=6, column=col, value=header)
cell.fill = light_blue
cell.font = bold_font
cell.alignment = Alignment(horizontal='center', wrap_text=True)
blue_font = Font(color="0000FF")
companies = [
["MSFT", 261400, 0.123, 179100, None, 205100, None],
["GOOGL", 349800, 0.118, 202500, None, 239300, None],
["AMZN", 638100, 0.105, 301800, None, 152600, None],
]
for row_idx, data in enumerate(companies, 7):
for col_idx, value in enumerate(data, 1):
cell = ws.cell(row=row_idx, column=col_idx)
if value is None:
if col_idx == 5:
cell.value = f"=D{row_idx}/B{row_idx}"
elif col_idx == 7:
cell.value = f"=F{row_idx}/B{row_idx}"
cell.font = Font(color="000000")
else:
cell.value = value
if col_idx in [2, 3, 4, 6]:
cell.font = blue_font
cell.comment = None
cell.alignment = Alignment(horizontal='center')
stats = ["最大值", "75 分位", "中位数", "25 分位", "最小值"]
stat_formulas = ["MAX", None, "MEDIAN", None, "MIN"]
grey_fill = PatternFill(start_color="F2F2F2", end_color="F2F2F2", fill_type="solid")
stat_row = 10
for i, stat_name in enumerate(stats):
row = stat_row + i
ws.cell(row=row, column=1, value=stat_name).fill = grey_fill
for col in range(2, 8):
cell = ws.cell(row=row, column=col)
if stat_name == "75 分位":
cell.value = f"=QUARTILE({get_column_letter(col)}7:{get_column_letter(col)}9,3)"
elif stat_name == "25 分位":
cell.value = f"=QUARTILE({get_column_letter(col)}7:{get_column_letter(col)}9,1)"
elif stat_name == "中位数":
cell.value = f"=MEDIAN({get_column_letter(col)}7:{get_column_letter(col)}9)"
else:
cell.value = f"={stat_formulas[i]}({get_column_letter(col)}7:{get_column_letter(col)}9)"
cell.fill = grey_fill
cell.alignment = Alignment(horizontal='center')
from openpyxl.styles import numbers
for row in range(7, 15):
for col in [3, 5, 7]:
ws.cell(row=row, column=col).number_format = '0.0%'
wb.save("可比公司分析.xlsx")
关键注意事项
公式写法:
cell.value = "=E7/C7"
cell.value = 0.687
添加单元格注释(数据来源):
from openpyxl.comments import Comment
comment = Comment("来源:东方财富网 - 贵州茅台 2024 年报\n获取日期:2025-06-10", "分析师")
cell.comment = comment
设置超链接:
cell.hyperlink = "https://www.cninfo.com.cn/new/disclosure/detail?plate=szse&stockCode=000858&announcementId=..."
cell.value = "2024 年年报"
cell.font = Font(color="0000FF", underline="single")
Section 8: 示例模板布局
简化版(从这里开始):
┌─────────────────────────────────────────────────────────────┐
│ 科技行业 - 可比公司分析 │
│ 微软 • 谷歌 • 亚马逊 │
│ 截至 2024 年 Q4 | 单位为 百万美元 │
├─────────────────────────────────────────────────────────────┤
│ 经营指标 │
├──────────┬─────────┬─────────┬──────────┬──────────────────┤
│ 公司 │ 营收 │ 增速 │ 毛利率 │ EBITDA │ EBITDA │
│ │ (LTM) │ (YoY) │ │ (LTM) │ 利润率 │
├──────────┼─────────┼─────────┼──────────┼────────┼────────┤
│ MSFT │ 261,400 │ 12.3% │ 68.7% │ 205,100│ 78.4% │
│ GOOGL │ 349,800 │ 11.8% │ 57.9% │ 239,300│ 68.4% │
│ AMZN │ 638,100 │ 10.5% │ 47.3% │ 152,600│ 23.9% │
│ │ │ │ │ │ │ [空行]
│ 中位数 │=MEDIAN │=MEDIAN │=MEDIAN │=MEDIAN│=MEDIAN │
│ 75 分位 │=QUART │=QUART │=QUART │=QUART │=QUART │
│ 25 分位 │=QUART │=QUART │=QUART │=QUART │=QUART │
├─────────────────────────────────────────────────────────────┤
│ 估值倍数 │
├──────────┬──────────┬──────────┬──────────┬────────────────┤
│ 公司 │ 市值 │ 企业价值 │ EV/营收 │ EV/EBITDA │ P/E │
├──────────┼──────────┼──────────┼──────────┼───────────┼────┤
│ MSFT │3,550,000 │3,530,000 │ 13.5x │ 17.2x │36.0 │
│ GOOGL │2,030,000 │1,960,000 │ 5.6x │ 8.2x │24.5 │
│ AMZN │2,226,000 │2,320,000 │ 3.6x │ 15.2x │58.3 │
│ │ │ │ │ │ │ [空行]
│ 中位数 │ =MEDIAN │ =MEDIAN │ =MEDIAN │ =MEDIAN │=MED│
│ 75 分位 │ =QUART │ =QUART │ =QUART │ =QUART │=QRT│
│ 25 分位 │ =QUART │ =QUART │ =QUART │ =QUART │=QRT│
└──────────┴──────────┴──────────┴──────────┴───────────┴────┘
只在需要时增加复杂度:
- 季节性重要时纳入季度和 LTM
- 现金创造是核心故事时增加 FCF 指标
- 行业特定指标(SaaS 的 Rule of 40 等)
- 公司超过 5 家时增加更多统计行
Section 9: 行业特定补充(可选)
只在指标对分析至关重要时添加。大多数 comps 用核心指标就够了。
软件/SaaS:
相关时添加:ARR、净收入留存率、Rule of 40
金融服务:
相关时添加:ROE、净息差、效率比
电商:
相关时添加:GMV、货币化率、活跃买家数
医疗:
相关时添加:研发/营收、管线价值、监管状态
制造业:
相关时添加:资产周转率、库存周转、在手订单
Section 10: 红旗与警示信号
数据质量问题
🚩 时间口径不一致(混用季度和年度)
🚩 缺失数据无解释
🚩 数据源间显著差异(>10%)
估值警示
🚩 EBITDA 为负的公司用 EBITDA 倍数估值(改用营收倍数)
🚩 P/E > 100x 却没有超高增速故事
🚩 利润率不符合行业常理
可比性问题
🚩 不同财年截止日(造成时间错位)
🚩 混用纯业务和多元化集团
🚩 商业模式差异大却被标为"同业"
拿不准时,剔除这家公司。 3 家完美可比 > 6 家 questionable。
Section 11: 公式速查
核心 Excel 公式
// 统计函数
=AVERAGE(区域) // 简单平均
=MEDIAN(区域) // 中位数
=QUARTILE(区域, 1) // 25 分位
=QUARTILE(区域, 3) // 75 分位
=MAX(区域) // 最大值
=MIN(区域) // 最小值
=STDEV.P(区域) // 标准差
// 财务计算
=B7/C7 // 简单比率(利润率)
=SUM(B7:B9)/3 // 多公司平均
=IF(B7>0, C7/B7, "N/A") // 条件计算
=IFERROR(C7/D7, 0) // 除零处理
// 跨表引用
='Sheet1'!B7 // 引用另一工作表
=VLOOKUP(A7, Table1, 2) // 数据表查找
=INDEX(MATCH()) // 高级查找
// 格式
=TEXT(B7, "0.0%") // 百分比格式
=TEXT(C7, "#,##0") // 千分位格式
常用比率公式
毛利率 = 毛利润 / 营收
EBITDA 利润率 = EBITDA / 营收
FCF 利润率 = 自由现金流 / 营收
FCF 转化率 = FCF / 经营现金流
ROE = 净利润 / 股东权益
ROA = 净利润 / 总资产
资产周转率 = 营收 / 总资产
负债权益比 = 总负债 / 股东权益
核心原则总结
- 结构驱动洞察 - 正确的表头迫使正确思考
- 少即是多 - 5-10 个关键指标胜过 20 个无关指标
- 为问题选指标 - 估值分析 ≠ 效率分析
- 统计展示模式 - 中位数/四分位比平均数揭示更多信息
- 透明胜于复杂 - 简单公式人人能懂
- 可比性是王道 - 宁可剔除也不要硬凑
- 记录你的选择 - 在注释区解释用了哪些指标及原因
交付前检查清单