comps-analysis · diff
git:20260826.8da358a to git:20260915.99ad826
183 added, 447 removed. Audit A to A.
---
name: comps-analysis
- description: "Comparable company analysis: operating metrics, valuation multiples, peer benchmarking"
- license: "Derived from anthropics/financial-services-plugins (Apache-2.0). Modified for langalpha."
+ description: "Comparable company analysis: peer set, operating metrics, valuation multiples, statistics and an implied value. Triggers on comps, trading comparables, how does it trade against peers, peer benchmarking, what multiple should it get."
---
# Comparable Company Analysis
- ## Overview
- This skill teaches Claude to build institutional-grade comparable company analyses that combine operating metrics, valuation multiples, and statistical benchmarking. The output is a structured Excel/spreadsheet that enables informed investment decisions through peer comparison.
-
- **ALWAYS ask yourself first:**
- 1. **"Do you have a preferred format or should I adapt the template style?"**
- 2. **"Who is the audience?"** (Investment committee, board presentation, quick reference, detailed memo)
- 3. **"What's the key question?"** (Valuation, growth analysis, competitive positioning, efficiency)
- 4. **"What's the context?"** (M&A evaluation, investment decision, sector benchmarking, performance review)
-
- **Adapt based on specifics:**
- - **Industry context**: Big tech mega-caps need different metrics than emerging SaaS startups
- - **Sector-specific needs**: Add relevant metrics early (e.g., cloud ARR, enterprise customers, developer ecosystem for tech)
- - **Company familiarity**: Well-known companies may need less background, more focus on delta analysis
- - **Decision type**: M&A requires different emphasis than ongoing portfolio monitoring
-
- **Core principle:** Use template principles (clear structure, statistical rigor, transparent formulas) but vary execution based on context. The goal is institutional-quality analysis, not institutional-looking templates.
-
- User-provided examples and explicit preferences always take precedence over defaults.
-
- ## Core Philosophy
- **"Build the right structure first, then let the data tell the story."**
-
- Start with headers that force strategic thinking about what matters, input clean data, build transparent formulas, and let statistics emerge automatically. A good comp should be immediately readable by someone who didn't build it.
-
- ---
-
- ## Section 1: Document Structure & Setup
-
- ### Header Block (Rows 1-3)
- ```
- Row 1: [ANALYSIS TITLE] - COMPARABLE COMPANY ANALYSIS
- Row 2: [List of Companies with Tickers] • [Company 1 (TICK1)] • [Company 2 (TICK2)] • [Company 3 (TICK3)]
- Row 3: As of [Period] | All figures in [USD Millions/Billions] except per-share amounts and ratios
- ```
-
- **Why this matters:** Establishes context immediately. Anyone opening this file knows what they're looking at, when it was created, and how to interpret the numbers.
-
- ### Visual Convention Standards
-
- > For all Excel formatting, number formats, and color standards, follow the guidelines in `.agents/skills/xlsx/SKILL.md`.
- > After generating Excel, run recalculation: `python .agents/skills/xlsx/scripts/recalc.py model.xlsx 30`
+ A comps table is arithmetic anyone can do and data discipline almost nobody does. The multiples are the easy half: the work is in which companies belong in the set, whether each number measures the same thing over the same period, and how old it is. The steps below build the table in the order those questions have to be answered.
- User-provided templates and explicit formatting preferences always override defaults.
+ Evidence labels, source tiers, staleness, the readiness posture and the intake limits: `.agents/skills/research-conventions/SKILL.md`, read before the first figure enters the table.
- ---
+ Period labels, per-company LTM windows, NTM as four quarterly estimates, and one common base date for every comparative return are binding here: `.agents/skills/research-conventions/references/market-data-rules.md`, read before the first pull. Step 3 adds no rule of its own and says only which of those period cases a comps table selects.
- ## Section 2: Operating Statistics & Financial Metrics
+ ## Step 1: Frame the table
- ### Core Columns (Start with these)
- 1. **Company** - Names with consistent formatting
- 2. **Revenue** - Size metric (can be LTM, quarterly, or annual depending on context)
- 3. **Revenue Growth** - Year-over-year percentage change
- 4. **Gross Profit** - Revenue minus cost of goods sold
- 5. **Gross Margin** - GP/Revenue (fundamental profitability)
- 6. **EBITDA** - Earnings before interest, tax, depreciation, amortization
- 7. **EBITDA Margin** - EBITDA/Revenue (operating efficiency)
+ Four questions decide what gets built. How many to ask, in what shape, and what to do when no answer comes back: `.agents/skills/research-conventions/references/intake.md`.
- ### Optional Additions (Choose based on industry/purpose)
- - **Quarterly vs LTM** - Include both if seasonality matters
- - **Free Cash Flow** - For capital-intensive or SaaS businesses
- - **FCF Margin** - FCF/Revenue (cash generation efficiency)
- - **Net Income** - For mature, profitable companies
- - **Operating Income** - For businesses with varying D&A
- - **CapEx metrics** - For asset-heavy industries
- - **Rule of 40** - Specifically for SaaS (Growth % + Margin %)
- - **FCF Conversion** - For quality of earnings analysis (advanced)
+ 1. **Format**: their template, or ours
+ 2. **Audience**: investment committee, board, quick reference, detailed memo
+ 3. **The key question**: valuation, growth, competitive position, efficiency
+ 4. **The context**: M&A, an investment decision, sector benchmarking, performance review
- ### Formula Examples (Using Row 7 as example)
- ```excel
- // Core ratios - these are always calculated
- Gross Margin (F7): =E7/C7
- EBITDA Margin (H7): =G7/C7
+ The answers change the table, not just its wrapper. A relative-value question needs multiples and quartiles; an efficiency question needs margins and turns and can drop the multiples entirely. Big-cap incumbents and emerging names in the same sector do not take the same metrics. User-provided examples and stated preferences outrank every default in this file.
- // Optional ratios - include if relevant
- FCF Margin: =[FCF]/[Revenue]
- Net Margin: =[Net Income]/[Revenue]
- Rule of 40: =[Growth %]+[FCF Margin %]
- ```
+ **Done when** the question the table answers is written down in one sentence and the metric list follows from it.
- **Golden Rule:** Every ratio should be [Something] / [Revenue] or [Something] / [Something from this sheet]. Keep it simple.
+ ## Step 2: Build the peer set, with roles
- ### Statistics Block (After company data)
+ Every peer carries a role, and the roles are tiered so the headline statistic is not diluted by a name that was only ever context.
- **CRITICAL: Add statistics formulas for all comparable metrics (ratios, margins, growth rates, multiples).**
+ | Role | Tier | Belongs when |
+ |---|---|---|
+ | `core` | 1 | same business model, comparable economics and scale, and the same demand driver |
+ | `read-through` | 2 | partial overlap, kept because it prints one metric that informs the subject |
+ | `analogue` | 2 | different business, kept as a growth, margin or size analogue, and labelled as such |
+ | `excluded` | listed, not shown | a near-peer a reader would expect, with the reason it is out |
- ```
- [Leave one blank row for visual separation]
- - Maximum: =MAX(B7:B9)
- - 75th Percentile: =QUARTILE(B7:B9,3)
- - Median: =MEDIAN(B7:B9)
- - 25th Percentile: =QUARTILE(B7:B9,1)
- - Minimum: =MIN(B7:B9)
- ```
+ **Headline statistics come from tier 1 alone.** Tier 2 appears in the table for context, visibly separated, and never inside the median that drives the selected range. The excluded list is part of the deliverable: a reader who cannot see why the obvious comparable is missing assumes it was missed.
- **Columns that NEED statistics (comparable metrics):**
- - Revenue Growth %, Gross Margin %, EBITDA Margin %, EPS
- - EV/Revenue, EV/EBITDA, P/E, Dividend Yield %, Beta
+ Five to ten names in tier 1 is the working range. Below three, the median is one company's opinion: the selected-range hierarchy in Step 8 falls through to a single named analogue and the output is screen-grade under Step 10. Above ten, the set has stopped being a peer group.
- **Columns that DON'T need statistics (size metrics):**
- - Revenue, EBITDA, Net Income (absolute size varies by company scale)
- - Market Cap, Enterprise Value (not comparable across different-sized companies)
+ Exclude rather than stretch. The comparability tells: materially different business models labelled as comps, a pure-play sitting beside a conglomerate, a peer whose fiscal year end does not line up and has not been calendarised, negative EBITDA valued on an EBITDA multiple, and a peer whose revenue is recognised on a different basis (gross billings against net revenue).
- **Note:** Add one blank row between company data and statistics rows for visual separation. Do NOT add a "SECTOR STATISTICS" or "VALUATION STATISTICS" header row.
+ **Done when** every name carries a role and a tier, every exclusion carries a reason, and tier 1 holds three or more names or the screen-grade posture in Step 10 applies.
- **Why quartiles matter:** They show distribution, not just average. A 75th percentile multiple tells you what "premium" companies trade at.
+ ## Step 3: Fix the basis before the first pull
- ---
+ Every rule here is cheap now and expensive to retrofit once the table is written.
- ## Section 3: Valuation Multiples & Investment Metrics
+ **Reported or adjusted, decided once.** One basis for the whole table, applied to every peer, with the adjustments made to each name listed. Reported and adjusted are different metrics, and a table that mixes them compares two things that were never the same. Where a peer only discloses one of the two, either bridge it or mark the row not comparable and say why.
- ### Core Valuation Columns (Start with these)
- 1. **Company** - Same order as operating section
- 2. **Market Cap** - Current market valuation
- 3. **Enterprise Value** - Market Cap ± Net Debt/Cash
- 4. **EV/Revenue** - How much market pays per dollar of sales
- 5. **EV/EBITDA** - How much market pays per dollar of earnings
- 6. **P/E Ratio** - Price relative to net earnings
+ **Comparability, per peer and per line.** Three states: directly comparable, comparable after a stated adjustment, or not comparable with the reason. The state travels with the cell, not with the company: a peer can be directly comparable on revenue and not comparable on EBITDA.
- ### Optional Valuation Metrics (Choose based on context)
- - **FCF Yield** - FCF/Market Cap (for cash-focused analysis)
- - **PEG Ratio** - P/E/Growth Rate (for growth companies)
- - **Price/Book** - Market value vs. book value (for asset-heavy businesses)
- - **ROE/ROA** - Return metrics (for profitability comparison)
- - **Revenue/EBITDA CAGR** - Historical growth rates (for trend analysis)
- - **Asset Turnover** - Revenue/Assets (for operational efficiency)
- - **Debt/Equity** - Leverage (for capital structure analysis)
+ **Denominator pairing.** The numerator and the denominator have to belong to the same claim on the business, and to the same period:
- **Key Principle:** Include 3-5 core multiples that matter for your industry. Don't include every possible metric just because you can.
+ | Numerator | Pairs only with | Never with |
+ |---|---|---|
+ | Enterprise value | pre-financing metrics: revenue, EBITDA, EBIT, unlevered FCF | net income, EPS, book equity |
+ | Equity value or price | post-financing metrics: net income, EPS, equity FCF, book value | EBITDA, EBIT, revenue |
- ### Formula Examples
- ```excel
- // Core multiples - always include these
- EV/Revenue: =[Enterprise Value]/[LTM Revenue]
- EV/EBITDA: =[Enterprise Value]/[LTM EBITDA]
- P/E Ratio: =[Market Cap]/[Net Income]
+ The period matches on both sides: an LTM numerator over an NTM denominator is a number with no meaning, however carefully it was computed.
- // Optional multiples - include if data available
- FCF Yield: =[LTM FCF]/[Market Cap]
- PEG Ratio: =[P/E]/[Growth Rate %]
- ```
+ **Sign, scale and currency at ingestion.** Normalise when the data enters the sheet, not when it is used: one reporting currency for the table, one scale (millions or billions, stated in the header), and one sign convention. Record what was applied per peer, because the alternative is a silent factor of 1,000 in a single row.
- ### Cross-Reference Rule
- **CRITICAL:** Valuation multiples MUST reference the operating metrics section. Never input the same raw data twice. If revenue is in C7, then EV/Revenue formula should reference C7.
+ **FX.** Balance-sheet items convert at spot, flow items at the period average, and the table states which currency and which convention. A peer reporting in another currency and translated at spot for revenue overstates or understates growth by the currency move alone.
- ### Statistics Block
- Same structure as operating section: Max, 75th, Median, 25th, Min for every metric. Add one blank row for visual separation between company data and statistics. Do NOT add a "VALUATION STATISTICS" header row.
+ **Calendarisation.** The period rule has three cases, and a comps table takes the first for every LTM column:
- ---
+ - an LTM multiple takes each company's own latest four reported quarters, per peer, with the four quarters recorded beside the name. A peer that has reported one quarter further than the subject carries that quarter,
+ - a calendarised comparison is a separate column of its own, built only for the forward or fiscal-year estimates that need one calendar year: sum the quarters falling inside it and head the column `calendarised to CY20XX`. An LTM column relabelled as a calendar year is a different metric wearing the label,
+ - a historical analysis takes the window each figure was true for, carrying its own as-of.
- ## Section 4: Notes & Methodology Documentation
+ State the method and the window on the table. A peer whose quarterly detail does not support a calendarised column is marked as reporting on its own year end and kept out of the tier 1 statistic for that column.
- ### Required Components
+ **Done when** the basis, the currency, the scale, the FX convention and the calendarisation window are written in the table's header block or its notes, and every peer has been normalised to them.
- **Data Sources & Quality:**
- - Where did the data come from? (fundamentals MCP, `get_company_overview`, SEC filings)
- - What period does it cover? (Q4 2024, audited figures)
- - How was it verified? (Cross-checked against 10-K/10-Q)
+ ## Step 4: Pull the data, with an as-of on every row
- **Key Definitions:**
- - EBITDA calculation method (Gross Profit + D&A, or Operating Income + D&A)
- - Free Cash Flow formula (Operating CF - CapEx)
- - Special metrics explained (Rule of 40, FCF Conversion)
- - Time period definitions (LTM, CAGR calculation periods)
+ - fundamentals MCP: `get_financial_statements(symbol, 'all', 'annual', 5)` for the statements, `get_financial_ratios(symbol)` for ratios, `get_growth_metrics(symbol)` for growth, `get_historical_valuation(symbol)` for the enterprise-value history behind the EV multiples (the multiples themselves come from `get_financial_ratios`)
+ - `get_company_overview` for market cap, consensus, price targets and rating distribution
+ - `get_sec_filing` where the tool figure and the filing disagree, and the filing settles it
- **Valuation Methodology:**
- - How was Enterprise Value calculated? (Market Cap + Net Debt)
- - What growth rates were used? (Historical CAGR, forward estimates)
- - Any adjustments made? (One-time items excluded, normalized margins)
+ **Every row carries an as-of column**: the date of the reporting period behind its fundamentals, not the date you pulled them. Prices, market caps and every multiple built on them carry the retrieval date as well, in the header block, since they move daily.
- **Analysis Framework:**
- - What's the investment thesis? (Cloud/SaaS efficiency)
- - What metrics matter most? (Cash generation, capital efficiency)
- - How should readers interpret the statistics? (Quartiles provide context)
+ The freshness threshold for each data type, the six staleness states and the conflict register are in `.agents/skills/research-conventions/references/evidence.md`. Reported financials there stay fresh until the company's next scheduled report; a peer that is past that date and has not filed is past its threshold rather than exempt, and the table below says what a comps row does about it rather than lifting the threshold:
- ---
+ | Age of the trailing period | Treatment |
+ |---|---|
+ | Within two quarters | usable |
+ | Two to four quarters | `aging`: usable for direction, with the reason beside the row saying why the peer has not reported |
+ | Beyond four quarters | not usable in a tier 1 statistic without a stated bridge: an interim update, a pre-announcement, or a calendarised partial year. Without the bridge the peer moves to tier 2 or out |
- ## Section 5: Choosing the Right Metrics (Decision Framework)
+ When two sources disagree on the same figure, name both, select by the source tiers in `evidence.md`, and disclose the discrepancy. Two figures averaged into a third that nobody reports is the failure this rule exists to prevent.
- ### Start with "What question am I answering?"
+ **Done when** every fundamentals cell has an as-of, every price-derived figure has a retrieval date, and no tier 1 row is beyond four quarters old without a bridge.
- **"Which company is undervalued?"**
- → Focus on: EV/Revenue, EV/EBITDA, P/E, Market Cap
- → Skip: Operational details, growth metrics
+ ## Step 5: Share count and the enterprise value bridge
- **"Which company is most efficient?"**
- → Focus on: Gross Margin, EBITDA Margin, FCF Margin, Asset Turnover
- → Skip: Size metrics, absolute dollar amounts
+ The dilution the market prices is not the basic share count, and the EV a table ships is often nobody's EV.
- **"Which company is growing fastest?"**
- → Focus on: Revenue Growth %, EBITDA CAGR, User/Customer Growth
- → Skip: Margin metrics, leverage ratios
+ **Dilution protocol**, applied per peer and named on the table:
- **"Which is the best cash generator?"**
- → Focus on: FCF, FCF Margin, FCF Conversion, CapEx intensity
- → Skip: EBITDA, P/E ratios
+ - **Options and warrants in the money**: treasury stock method. Shares issued on exercise, less the shares repurchasable with the proceeds at the current price. Out-of-the-money grants are excluded, and the strike distribution comes from the equity footnote
+ - **Convertibles in the money**: if-converted. Add the conversion shares, and for an earnings-based multiple add back the after-tax interest to the numerator. Out of the money, the instrument stays in debt
+ - **Unvested RSUs**: included at their gross count; there are no proceeds to net against
+ - Show the share count build rather than a single number, and name the method beside it
- ### Industry-Specific Metric Selection
+ **The EV bridge, reconciled.** Compute both sides independently and compare:
- **Software/SaaS:**
- Must have: Revenue Growth, Gross Margin, Rule of 40
- Optional: ARR, Net Dollar Retention, CAC Payback
- Skip: Asset Turnover, Inventory metrics
+ ```
+ Market cap = price x diluted shares
+ Enterprise value = market cap + total debt + preferred + minority interest - cash and equivalents
+ ```
- **Manufacturing/Industrials:**
- Must have: EBITDA Margin, Asset Turnover, CapEx/Revenue
- Optional: ROA, Inventory Turns, Backlog
- Skip: Rule of 40, SaaS metrics
+ Compare the computed market cap and enterprise value against the reference figures from `get_company_overview`. **A gap beyond 2 percent is a finding, not a rounding difference**: it usually means a different share count, a stale price, or a claim (leases, pensions, non-controlling interests) that one side counts and the other does not. Resolve it, or disclose the difference and its cause on the table. Both comparisons are rows on the `Checks` sheet.
- **Financial Services:**
- Must have: ROE, ROA, Efficiency Ratio, P/E
- Optional: Net Interest Margin, Loan Loss Reserves
- Skip: Gross Margin, EBITDA (not meaningful for banks)
+ **Done when** every peer's share count names its method, and the market cap and EV reconciliations are within 2 percent or carry a stated cause.
- **Retail/E-commerce:**
- Must have: Revenue Growth, Gross Margin, Inventory Turnover
- Optional: Same-Store Sales, Customer Acquisition Cost
- Skip: Heavy R&D or CapEx metrics
+ ## Step 6: Choose the metrics
- ### The "5-10 Rule"
+ Start from the question, not from the list of everything computable.
- **5 operating metrics** - Revenue, Growth, 2-3 margins/efficiency metrics
- **5 valuation metrics** - Market Cap, EV, 3 multiples
- **= 10 total columns** - Enough to tell the story, not so many you lose the thread
+ | The question | Focus on | Drop |
+ |---|---|---|
+ | Which company is undervalued | EV/Revenue, EV/EBITDA, P/E, market cap | operating detail, growth breakdowns |
+ | Which is most efficient | gross margin, EBITDA margin, FCF margin, asset turnover | size metrics, absolute dollars |
+ | Which is growing fastest | revenue growth, EBITDA CAGR, customer or unit growth | margin and leverage metrics |
+ | Which generates the most cash | FCF, FCF margin, FCF conversion, capex intensity | EBITDA multiples, P/E |
- If you have more than 15 metrics, you're probably including noise. Edit ruthlessly.
+ **Core operating columns**: company, revenue, revenue growth, gross profit, gross margin, EBITDA, EBITDA margin.
+ **Core valuation columns**: company, market cap, enterprise value, EV/Revenue, EV/EBITDA, P/E.
- ---
+ Add by sector, and only what changes a conclusion:
- ## Section 6: Best Practices & Quality Checks
+ | Sector | Must have | Skip |
+ |---|---|---|
+ | Software and SaaS | revenue growth, gross margin, Rule of 40 on FCF margin; optionally ARR, net dollar retention, CAC payback | asset turnover, inventory metrics |
+ | Manufacturing and industrials | EBITDA margin, asset turnover, capex/revenue; optionally ROA, inventory turns, backlog | Rule of 40 on FCF margin |
+ | Financial services | ROE, ROA, efficiency ratio, P/E; optionally net interest margin, reserves | gross margin, EBITDA, which are not meaningful for a bank |
+ | Retail and e-commerce | revenue growth, gross margin, inventory turnover; optionally same-store sales, GMV, take rate | heavy R&D or capex metrics |
+ | Healthcare | R&D/revenue, EBITDA margin, growth; optionally pipeline value, patent timeline | inventory-driven metrics |
- ### Before You Start
- 1. **Define the peer group** - Companies must be truly comparable (similar business model, scale, geography)
- 2. **Choose the right period** - LTM smooths seasonality; quarterly shows trends
- 3. **Standardize units upfront** - Millions vs. billions decision affects everything
- 4. **Map data sources** - Know where each number comes from
+ **The 5-10 rule**: five operating metrics, five valuation metrics, ten columns. Past fifteen you are including noise. Include three to five multiples that matter for the sector rather than every multiple that computes.
- ### As You Build
- 1. **Input all raw data first** - Complete the blue text before writing formulas
- 2. **Add cell comments to ALL hard-coded inputs** - Right-click cell → Insert Comment → Document source OR assumption
+ **Done when** every column either appears in the metric list written down in Step 1 or is identification or provenance metadata (name, ticker, role and tier, as-of, source), and the count is at or under ten.
- **For sourced data, cite exactly where it came from:**
- - Example: "fundamentals MCP get_financial_statements(MSFT, 'all', 'annual', 5), accessed 2024-10-02"
- - Example: "Q4 2024 10-K filing, page 42, line item 'Total Revenue'"
- - Example: "get_company_overview(MSFT) — analyst consensus as of 2024-10-02"
- - **Include hyperlinks when possible**: Right-click cell → Link → paste URL to SEC filing, data source, or report
+ ## Step 7: Build the workbook
- **For assumptions, explain the reasoning:**
- - Example: "Assumed 15% EBITDA margin based on peer median, company does not disclose"
- - Example: "Estimated Enterprise Value as Market Cap + $50M net debt (from Q3 balance sheet, Q4 not yet available)"
- - Example: "Forward P/E based on street consensus EPS of $3.45 (average of 12 analyst estimates)"
+ **Formulas, not hardcoded values.** Every derived value (margin, multiple, statistic, implied value) is a live Excel formula referencing the input cells. A number computed in Python and pasted in is a defect even when the value is right today. With openpyxl, `cell.value = "=E7/C7"` is correct and `cell.value = 0.687` is not. The only typed numbers are the raw inputs (revenue, EBITDA, share price, share count, net debt), and every one carries a cell comment naming its source, its as-of, and any adjustment applied. For an assumption rather than a source, the comment carries the reasoning and what would replace it.
- **Why this matters**: Enables audit trails, data verification, assumption transparency, and future updates
- 3. **Build formulas row by row** - Test each calculation before moving on
- 4. **Use absolute references for headers** - $C$6 locks the header row
- 5. **Format consistently** - Percentages as percentages, not decimals
- 6. **Add conditional formatting** - Highlight outliers automatically
+ **Build, present, recalc, audit.** Build from a saved Python script using openpyxl, following `.agents/skills/xlsx/SKILL.md`. Then run `python .agents/skills/xlsx/scripts/recalc.py <file> 30` until the status is "success", and `python .agents/skills/xlsx/scripts/audit.py <file> --strict` and fix every `fail`.
- ### Sanity Checks
- - **Margin test**: Gross margin > EBITDA margin > Net margin (always true by definition)
- - **Multiple reasonableness**:
- - EV/Revenue: typically 0.5-20x (varies widely by industry)
- - EV/EBITDA: typically 8-25x (fairly consistent across industries)
- - P/E: typically 10-50x (depends on growth rate)
- - **Growth-multiple correlation**: Higher growth usually means higher multiples
- - **Size-efficiency trade-off**: Larger companies often have better margins (scale benefits)
+ **Three sheets**: `Cover` first, then the comps table, then `Checks`. The cover's tiles are formulas linking to the selected statistic, the implied enterprise value, the implied equity value and the per-share value, and it is written once those cells are locked.
- ### Common Mistakes to Avoid
- ❌ Mixing market cap and enterprise value in formulas
- ❌ Using different time periods for numerator and denominator (LTM vs quarterly)
- ❌ Hardcoding numbers into formulas instead of cell references
- ❌ **Hard-coded inputs without cell comments citing the source OR explaining the assumption**
- ❌ Missing hyperlinks to SEC filings or data sources when available
- ❌ Including too many metrics without clear purpose
- ❌ Including non-comparable companies (different business models)
- ❌ Using outdated data without disclosure
- ❌ Calculating averages of percentages incorrectly (should be median)
+ Present each stage as you finish it rather than delivering the sheet complete. A PTC turn is not chat-interactive at every step, so this is not a blocking question: present the block, say what you are building next, and carry on unless the user objects. A bad peer or a mismatched period surfaces before the statistics and the implied value are built on top of it.
- ---
+ 1. **Peer set and structure** - the names, their roles and tiers, why each is comparable, and the column layout
+ 2. **Basis** - currency, scale, reported or adjusted, FX and calendarisation conventions
+ 3. **Raw inputs** - the input block, with the period, as-of and source behind each number
+ 4. **Share count and EV bridge** - the dilution build and both reconciliations
+ 5. **Operating metrics** - the calculated margins and growth rates
+ 6. **Valuation multiples** - the multiples, against the sanity ranges in Step 9
+ 7. **Statistics and selected range** - the quartile block, the outlier decisions, the selected statistic
+ 8. **Checks sheet** - the roll-up cell reading OK
- ## Section 6: Advanced Features
+ **Header block (rows 1 to 3):**
- ### Dynamic Headers
- For columns showing calculations, use clear unit labels:
```
- Revenue Growth (YoY) % | EBITDA Margin | FCF Margin | Rule of 40
+ Row 1: [ANALYSIS TITLE] - COMPARABLE COMPANY ANALYSIS
+ Row 2: [Company 1 (TICK1)] | [Company 2 (TICK2)] | [Company 3 (TICK3)]
+ Row 3: Prices as of [date] | Financials as of [period] | [USD millions] | [reported or adjusted] basis
```
- ### Quartile Analysis Benefits
- Instead of just mean/median, quartiles show:
- - **75th percentile** = "Premium" companies trade here
- - **Median** = Typical market valuation
- - **25th percentile** = "Discount" territory
-
- This helps answer: "Is our target company trading rich or cheap vs. peers?"
-
- ### Industry-Specific Modifications
-
- **Software/SaaS:**
- - Add: ARR, Net Dollar Retention, CAC Payback Period
- - Emphasize: Rule of 40, FCF margins, gross margins >70%
-
- **Healthcare:**
- - Add: R&D/Revenue, Pipeline value, Regulatory status
- - Emphasize: EBITDA margins, growth rates, reimbursement risk
-
- **Industrials:**
- - Add: Backlog, Order book trends, Geographic mix
- - Emphasize: ROIC, asset turnover, cyclical adjustments
-
- **Consumer:**
- - Add: Same-store sales, Customer acquisition cost, Brand value
- - Emphasize: Revenue growth, gross margins, inventory turns
-
- ---
-
- ## Section 7: Workflow & Practical Tips
-
- ### Step-by-Step Process
- 1. **Set up structure** (30 minutes)
- - Create all headers
- - Format cells (blue for inputs, black for formulas)
- - Lock in units and date references
-
- 2. **Gather data**
- - Use fundamentals MCP: `get_financial_statements(symbol, 'all', 'annual', 5)` for income statement, balance sheet, cash flow
- - Use fundamentals MCP: `get_financial_ratios(symbol)` for pre-computed ratios and margins
- - Use fundamentals MCP: `get_growth_metrics(symbol)` for historical growth rates
- - Use `get_company_overview` tool for market cap, analyst consensus, price targets, rating distribution
- - Use fundamentals MCP: `get_historical_valuation(symbol)` for valuation multiples
- - Input all raw numbers in blue
- - Document sources in notes section
-
- 3. **Build formulas** (30 minutes)
- - Start with simple ratios (margins)
- - Progress to multiples (EV/Revenue)
- - Add cross-checks (do margins make sense?)
-
- 4. **Add statistics** (15 minutes)
- - Copy formula structure for all columns
- - Verify ranges are correct (B7:B9, not B7:B10)
- - Check quartile logic
-
- 5. **Quality control** (30 minutes)
- - Run sanity checks
- - Verify formula references
- - Check for #DIV/0! or #REF! errors
- - Compare against known benchmarks
-
- 6. **Documentation** (15 minutes)
- - Complete notes section
- - Add data sources
- - Define methodologies
- - Date-stamp the analysis
-
- ### Pro Tips
- - **Save templates**: Build once, reuse forever
- - **Color-code outliers**: Conditional formatting for values >2 standard deviations
- - **Link to source files**: Hyperlink to SEC filings or data source references
- - **Version control**: Save as "Comps_v1_2024-12-15" with clear dating
- - **Collaborative reviews**: Have someone else check your formulas
-
- ### Excel Formatting Checklist
+ **Ratios**: every one is `[something] / [revenue]` or `[something] / [something on this sheet]`. `Gross Margin (F7): =E7/C7`, `EBITDA Margin (H7): =G7/C7`, `Rule of 40 on FCF margin: =[growth %]+[FCF margin %]`, named that way on the sheet so it is never confused with the EBITDA-margin variant.
- > For all Excel formatting, number formats, and color standards, follow the guidelines in `.agents/skills/xlsx/SKILL.md`.
- > After generating Excel, run recalculation: `python .agents/skills/xlsx/scripts/recalc.py model.xlsx 30`
+ **Cross-reference rule**: valuation multiples reference the operating cells. Never input the same raw number twice. If revenue is in C7, EV/Revenue divides by C7.
- - [ ] **One blank row for separation between company data and statistics rows**
- - [ ] **No separate "SECTOR STATISTICS" or "VALUATION STATISTICS" header rows**
- - [ ] **Every hard-coded input cell has a comment with either: (1) exact data source, OR (2) assumption explanation**
- - [ ] **Hyperlinks added to cells where applicable** (SEC filings, data source references)
+ **Done when** the workbook rebuilds from the saved script, `audit.py --strict` reports no `fail`, and no derived cell holds a typed number.
- ---
+ ## Step 8: Statistics, outliers and the selected range
- ## Section 8: Example Template Layout
+ **The statistics block**, below one blank row, with no "SECTOR STATISTICS" or "VALUATION STATISTICS" header row:
- **Simple Version (Start here):**
```
- ┌─────────────────────────────────────────────────────────────┐
- │ TECHNOLOGY - COMPARABLE COMPANY ANALYSIS │
- │ Microsoft • Alphabet • Amazon │
- │ As of Q4 2024 | All figures in USD Millions │
- ├─────────────────────────────────────────────────────────────┤
- │ OPERATING METRICS │
- ├──────────┬─────────┬─────────┬──────────┬──────────────────┤
- │ Company │ Revenue │ Growth │ Gross │ EBITDA │ EBITDA │
- │ │ (LTM) │ (YoY) │ Margin │ (LTM) │ Margin │
- ├──────────┼─────────┼─────────┼──────────┼─────────┼────────┤
- │ 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% │
- │ │ │ │ │ │ │ [blank row]
- │ Median │ =MEDIAN │ =MEDIAN │ =MEDIAN │ =MEDIAN │=MEDIAN │
- │ 75th % │ =QUART │ =QUART │ =QUART │ =QUART │=QUART │
- │ 25th % │ =QUART │ =QUART │ =QUART │ =QUART │=QUART │
- ├─────────────────────────────────────────────────────────────┤
- │ VALUATION MULTIPLES │
- ├──────────┬──────────┬──────────┬──────────┬────────────────┤
- │ Company │ Mkt Cap │ EV │ EV/Rev │ 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│
- │ │ │ │ │ │ │ [blank row]
- │ Median │ =MEDIAN │ =MEDIAN │ =MEDIAN │ =MEDIAN │=MED│
- │ 75th % │ =QUART │ =QUART │ =QUART │ =QUART │=QRT│
- │ 25th % │ =QUART │ =QUART │ =QUART │ =QUART │=QRT│
- └──────────┴──────────┴──────────┴──────────┴───────────┴────┘
+ Maximum: =MAX(B7:B9)
+ 75th Percentile: =QUARTILE(B7:B9,3)
+ Median: =MEDIAN(B7:B9)
+ 25th Percentile: =QUARTILE(B7:B9,1)
+ Minimum: =MIN(B7:B9)
```
- **Add complexity only when needed:**
- - Include quarterly AND LTM if seasonality matters
- - Add FCF metrics if cash generation is key story
- - Include industry-specific metrics (Rule of 40 for SaaS, etc.)
- - Add more statistics rows if you have >5 companies
-
- ---
-
- ## Section 9: Industry-Specific Additions (Optional)
-
- Only add these if they're critical to your analysis. Most comps work fine with just core metrics.
+ Statistics belong on comparable metrics: growth rates, margins, EPS, EV/Revenue, EV/EBITDA, P/E, dividend yield, beta. They do not belong on size metrics (revenue, EBITDA, net income, market cap, enterprise value), where the spread is the scale of the companies rather than a valuation signal.
- **Software/SaaS:**
- Add if relevant: ARR, Net Dollar Retention, Rule of 40
+ Quartiles carry information a mean does not: the 75th percentile is what the market pays for the premium names in this set, the 25th is discount territory, and the gap between them is how much the set actually agrees.
- **Financial Services:**
- Add if relevant: ROE, Net Interest Margin, Efficiency Ratio
+ **Outliers, by a stated rule.** A value is an outlier when it sits more than 1.5 interquartile ranges below the 25th percentile or above the 75th. Then decide, per outlier, and record the decision on the sheet:
- **E-commerce:**
- Add if relevant: GMV, Take Rate, Active Buyers
+ - **trim** it from the statistic, with the row still visible in the table,
+ - **keep** it with a note explaining why it is real (a genuine premium, a distressed name, a different growth rate),
+ - **exclude** the peer entirely, which moves it to the excluded list in Step 2 with its reason.
- **Healthcare:**
- Add if relevant: R&D/Revenue, Pipeline Value, Patent Timeline
+ Never silently drop a name: a table whose statistic quietly omits a peer cannot be reproduced by the reader.
- **Manufacturing:**
- Add if relevant: Asset Turnover, Inventory Turns, Backlog
+ **The selected range, by hierarchy.** Test the exceptional conditions first and take the first that holds, since the median is the default only where none of them do. Say which one applied:
- ---
+ 1. The single closest analogue, named as such, when fewer than three tier 1 names survive. This is a screen-grade output under Step 10
+ 2. The trimmed mean, when one recorded outlier is doing the distorting and the rest of the set is tight
+ 3. The tier 1 interquartile band, when the set disagrees with itself by more than roughly half a turn
+ 4. The tier 1 median, when three or more tier 1 names survive and none of the above holds
- ## Section 10: Red Flags & Warning Signs
+ Apply the selected statistic to the subject's own metric, on the same basis and the same period, to get the implied value. The implied enterprise value bridges to equity value through the same claims as Step 5, in reverse.
- ### Data Quality Issues
- 🚩 Inconsistent time periods (mixing quarterly and annual)
- 🚩 Missing data without explanation
- 🚩 Significant differences between data sources (>10% variance)
+ **Done when** every outlier has a recorded decision, the selected statistic names which hierarchy rung it came from, and the implied value is a formula over the statistic and the subject's metric.
- ### Valuation Red Flags
- 🚩 Negative EBITDA companies being valued on EBITDA multiples (use revenue multiples instead)
- 🚩 P/E ratios >100x without hypergrowth story
- 🚩 Margins that don't make sense for the industry
+ ## Step 9: Sanity checks and the failure list
- ### Comparability Issues
- 🚩 Different fiscal year ends (causes timing problems)
- 🚩ixing pure-play and conglomerates
- 🚩 Materially different business models labeled as "comps"
+ - **Margin ordering**: gross margin above EBITDA margin above net margin, always, by definition. A violation is a data error
+ - **Multiple ranges**: EV/Revenue usually 0.5x to 20x and wildly sector-dependent, EV/EBITDA usually 8x to 25x, P/E usually 10x to 50x against the growth rate. Outside those, find the reason before shipping the cell
+ - **Growth against multiple**: higher growth generally carries a higher multiple. A high-growth name at the bottom of the range is either a finding or an error, and it is worth knowing which
+ - **A P/E above 100x** with no hypergrowth story, and a negative-EBITDA company carrying an EBITDA multiple, are both cells that should not have been computed
- **When in doubt, exclude the company.** Better to have 3 perfect comps than 6 questionable ones.
+ The mistakes that ship most often: market cap and enterprise value mixed in one formula; different periods across a numerator and a denominator; a hardcoded number where a reference belongs; an input with no source comment; a peer whose fiscal year end was never calendarised; a mean where a median belongs; and data used past its threshold with no disclosure.
- ---
+ **Done when** every sanity check has been run against the built sheet and each violation has either a fix or a stated reason.
- ## Section 11: Formulas Reference Guide
+ ## Step 10: Output
- ### Essential Excel Formulas
- ```excel
- // Statistical Functions
- =AVERAGE(range) // Simple mean
- =MEDIAN(range) // Middle value
- =QUARTILE(range, 1) // 25th percentile
- =QUARTILE(range, 3) // 75th percentile
- =MAX(range) // Maximum value
- =MIN(range) // Minimum value
- =STDEV.P(range) // Standard deviation
+ **Posture, once, near the top.** The ladder is in `.agents/skills/research-conventions/SKILL.md`. Comps reaches `screen-grade` more often than any other deliverable in this plugin, and reaching it honestly beats the two failure modes on either side of it.
- // Financial Calculations
- =B7/C7 // Simple ratio (Margin)
- =SUM(B7:B9)/3 // Average of multiple companies
- =IF(B7>0, C7/B7, "N/A") // Conditional calculation
- =IFERROR(C7/D7, 0) // Handle divide by zero
+ **The screen-grade fallback.** When the data will not support a decision-grade table, still emit the table. Label every unavailable cell as unavailable rather than leaving it blank or filling it with an estimate, name what is missing and what would supply it, and set the posture to `screen-grade`. A blank cell reads as zero to half of readers and as an oversight to the other half; a labelled one reads as what it is. Refusing to produce anything is the other failure: the peer set and the metrics that do exist are useful even when three cells are not.
- // Cross-Sheet References
- ='Sheet1'!B7 // Reference another sheet
- =VLOOKUP(A7, Table1, 2) // Lookup from data table
- =INDEX(MATCH()) // Advanced lookup
+ **The handoff block**, a fixed set of fields for whoever consumes the table next, whether that is a model, a memo or a person:
- // Formatting
- =TEXT(B7, "0.0%") // Format as percentage
- =TEXT(C7, "#,##0") // Thousands separator
```
-
- ### Common Ratio Formulas
- ```excel
- Gross Margin = Gross Profit / Revenue
- EBITDA Margin = EBITDA / Revenue
- FCF Margin = Free Cash Flow / Revenue
- FCF Conversion = FCF / Operating Cash Flow
- ROE = Net Income / Shareholders' Equity
- ROA = Net Income / Total Assets
- Asset Turnover = Revenue / Total Assets
- Debt/Equity = Total Debt / Shareholders' Equity
+ As-of: prices [date], financials [period]
+ Peer set: tier 1 names and roles; tier 2 names and roles; exclusions with reasons
+ Statistic used: which rung of the selected-range hierarchy, and its value
+ Basis: reported or adjusted, currency, scale, calendarisation window
+ Denominator: the subject metric the statistic was applied to, and its period
+ Implied EV: value
+ Claims bridged: debt, preferred, minority interest, cash, leases, pensions
+ Implied equity value: value
+ Per-share value: value, and the share count method behind it
+ Limitations: what is stale, what is missing, what is not comparable
```
- ---
-
- ## Key Principles Summary
+ **Notes and methodology**, on the sheet: where each number came from and how it was verified; the definitions in use (which EBITDA build, which FCF formula, how LTM was computed per peer); how enterprise value was constructed and which claims are in it; and what a reader should take from the quartiles.
- 1. **Structure drives insight** - Right headers force right thinking
- 2. **Less is more** - 5-10 metrics that matter beat 20 that don't
- 3. **Choose metrics for your question** - Valuation analysis ≠ efficiency analysis
- 4. **Statistics show patterns** - Median/quartiles reveal more than average
- 5. **Transparency beats complexity** - Simple formulas everyone understands
- 6. **Comparability is king** - Better to exclude than force a bad comp
- 7. **Document your choices** - Explain which metrics and why in notes section
+ **Confidence, in one sentence**, with its reasons: how tight the tier 1 set is, how fresh the data is, and how much adjustment the table needed to make the peers comparable.
- ---
+ **Done when** the posture, the handoff block and the confidence sentence are all present, and no unavailable cell is blank.
- ## Output Checklist
+ ## Checks Sheet (Required)
- Before delivering a comp analysis, verify:
- - [ ] All companies are truly comparable
- - [ ] Data is from consistent time periods
- - [ ] Units are clearly labeled (millions/billions)
- - [ ] Formulas reference cells, not hardcoded values
- - [ ] **All hard-coded input cells have comments with either: (1) exact data source with citation, OR (2) clear assumption with explanation**
- - [ ] **Hyperlinks added where relevant** (SEC EDGAR filings, research reports)
- - [ ] Statistics include at least 5 metrics (Max, 75th, Med, 25th, Min)
- - [ ] Notes section documents sources and methodology
- - [ ] Visual formatting follows conventions (blue = input, black = formula)
- - [ ] Sanity checks pass (margins logical, multiples reasonable)
- - [ ] Date stamp is current ("As of [Date]")
- - [ ] Formula auditing shows no errors (#DIV/0!, #REF!, #N/A)
+ Every comps workbook carries a `Checks` sheet. The four-column layout, the verdict formula, the roll-up and the read-back after recalculation are the sheet contract under *Financial Model Conventions* in `.agents/skills/xlsx/SKILL.md`. The rows a comps table has to carry:
- ---
+ | Check | Column B holds | Verdict |
+ |---|---|---|
+ | Every peer has a ticker | `=COUNTA(<peer name block>)-COUNTA(<ticker block>)`; column C tests `=0` | FAIL |
+ | No duplicate peers | `=COUNTA(<ticker block>)-SUMPRODUCT(1/COUNTIF(<ticker block>,<ticker block>))`; column C tests `=0` | FAIL |
+ | Every peer has a role and a tier | `=COUNTA(<ticker block>)-COUNTA(<role block>)`; column C tests `=0` | FAIL |
+ | Every peer has an as-of | `=COUNTA(<ticker block>)-COUNT(<as-of block>)`; column C tests `=0` | FAIL |
+ | No tier 1 row is stale | `=MAX(<today> - <tier 1 as-of block>)`; column C tests against the four-quarter bound | WARN |
+ | Market cap reconciles | For each peer, the largest absolute percentage gap between the computed market cap and the reference market cap; column C tests `<0.02` | WARN |
+ | Enterprise value reconciles | Same, for enterprise value against its reference; column C tests `<0.02` | WARN |
+ | Diluted share count exceeds basic | `=MIN(<diluted block> - <basic block>)`; column C tests `>=0` | FAIL |
+ | Multiples equal EV or price over the denominator | For each multiple column, the largest absolute difference across the peer block between the multiple cell and enterprise value (or price) divided by its metric | FAIL |
+ | Median and mean rows are formulas over the tier 1 block | Median cell minus `=MEDIAN(<tier 1 block>)`, and mean cell minus `=AVERAGE(<tier 1 block>)`, one row each | FAIL |
+ | Target implied value ties to the chosen multiple | Implied value minus (the selected statistic times the target's metric) | FAIL |
+ | Implied equity value ties to the bridge | Implied equity value minus (implied EV - net debt - other claims) | FAIL |
- ## Continuous Improvement
+ The build script writes this sheet **last**, once the peer block and the statistics rows exist and their row positions are locked, so the check formulas point at final addresses. Links into another workbook are `audit.py`'s job, under `references_external`, so no row here counts them. A FAIL blocks delivery: fix the sheet, not the check. A WARN either gets a fix or gets its reason in column D and one sentence in the delivery saying why the table is right and the band is not.
- After completing a comp analysis, ask:
- 1. Did the statistics reveal unexpected insights?
- 2. Were there any data gaps that limited analysis?
- 3. Did stakeholders ask for metrics you didn't include?
- 4. How long did it take vs. how long should it take?
- 5. What would make this more useful next time?
+ ## Output Checklist
- The best comp analyses evolve with each iteration. Save templates, learn from feedback, and refine the structure based on what decision-makers actually use.
+ - [ ] Every peer carries a role and a tier; exclusions listed with reasons; headline statistics from tier 1 only
+ - [ ] Every row carries an as-of; prices and multiples carry a retrieval date; no tier 1 row past four quarters without a bridge
+ - [ ] One basis, currency, scale, FX convention and calendarisation window, stated on the sheet
+ - [ ] Every numerator paired with a matching denominator on a matching period
+ - [ ] Share count method named per peer; market cap and EV both reconcile within 2 percent or carry a stated cause
+ - [ ] Outlier decisions recorded; the selected statistic names its hierarchy rung
+ - [ ] Formulas reference cells; every input has a source or assumption comment; hyperlinks where a filing supports one
+ - [ ] `Cover` is the first sheet, its tiles linking to the selected statistic, the implied EV, the implied equity value and the per-share value
+ - [ ] `recalc.py` reports "success"; `audit.py --strict` reports no `fail`; `Overall` reads OK and the `Diagnostics open` count is read back, both with `data_only=True`
+ - [ ] Sanity checks pass, or each violation carries a stated reason
+ - [ ] Posture, handoff block and confidence sentence present; unavailable cells labelled rather than blank