Skip to main content
skill CX Codex

company-valuation — Claude Code skill: what it does, how to install

Estimates a public company's intrinsic value using DCF, peer multiples, and SOTP. The skill generates a WACC sensitivity grid and bull, base, or bear price targets.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add himself65/finance-skills --skill company-valuation -a claude-code
Open on GitHub

What company-valuation does

Instead of relying on LLM memory, this skill executes Python models to evaluate equity value. It triangulates fair value using three approaches: a 5-year discounted cash flow with WACC discounting, peer valuation against 4–6 competitors using median EV/EBITDA, P/E, or EV/Revenue, and sum-of-the-parts for multi-segment businesses. The output includes a 5×5 sensitivity table crossing WACC against terminal growth rates alongside bull, base, and bear scenarios.

Execution relies on Python 3 with yfinance, numpy, and pandas. If these packages are missing, the setup flow triggers python3 -m pip install -q yfinance numpy pandas. It pulls live 10-year US Treasury yields for the risk-free rate, falling back to 4.5% if the ticker fetch fails.

Valuation logic adapts to sector profiles. DCF is skipped for banks, REITs, and pre-revenue companies in favor of specialized book value or revenue multiples. Without shell execution permissions, the agent cannot pull SEC filings or pricing data and will halt.

What it helps with

  • calculate public company intrinsic value using a 5-year DCF model
  • benchmark valuation against peer medians using EV/EBITDA and P/E
  • break down multi-segment corporate valuation with SOTP
  • generate a 5×5 WACC and terminal growth sensitivity matrix

Example prompts for the agent

  • Run a DCF valuation for AAPL and calculate implied share price
  • Value MSFT using peer multiples and build bull, base, and bear scenarios
  • Perform a sum-of-the-parts valuation for this conglomerate

How to install company-valuation

1Skills CLI (Vercel)

npx skills add himself65/finance-skills --skill company-valuation -a claude-code

2Manually: put the files in place

~/.claude/skills/company-valuation/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/company-valuation/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about company-valuation

How to install company-valuation in Claude Code?

Run npx skills add himself65/finance-skills --skill company-valuation -a claude-code in your terminal.

What does company-valuation do?

It estimates a stock's intrinsic fair value by combining 5-year DCF projections, peer multiples, and segment-level SOTP analysis. It also outputs upside or downside versus current market price and sensitivity grids.

What dependencies are required?

The skill requires shell access and Python 3 with yfinance, numpy, and pandas. Missing packages can be installed using python3 -m pip install -q yfinance numpy pandas.

Source text

SKILL.md · MIT
---
name: company-valuation
description: >
  Estimate a public company's intrinsic value with DCF, relative (peer multiple), and
  sum-of-the-parts (SOTP) methods, then blend them into an implied share price with
  upside/downside vs the market price, a WACC and terminal-growth sensitivity grid,
  and bull/base/bear scenarios. Use this skill whenever the user asks what a company
  or ticker is worth: fair value, intrinsic value, implied share price, a price target
  from fundamentals, whether it is overvalued or undervalued, building a DCF (WACC,
  terminal value, discounted cash flow), EV/EBITDA or P/E based targets, peer
  comparison valuation, or SOTP and conglomerate discounts. Run the model rather than
  answering valuation questions from memory.
---

# Company Valuation

If your host has not already executed the shell probes below (for example, in Codex), run the commands inside the `!` wrappers with its shell tool before choosing a setup path. Use the actual output; if shell access is unavailable, report that limitation.

Triangulates intrinsic value via three methods, then blends them to an implied share price:

1. **DCF** — 5-year FCFF projection, discount at WACC, terminal value.
2. **Relative** — apply peer median P/E, EV/Revenue, EV/EBITDA.
3. **SOTP** — when 2+ distinct reporting segments exist, value each at pure-play peer multiples.

Always present a WACC × terminal-growth sensitivity table and Bull/Base/Bear scenarios.

**Disclaimer**: Research/educational output. Not financial advice.

---

## Step 1: Detection Flow

Detect data source and runtime deps. The skill supports 2 method paths — pick the richest one available.

**Environment status:**

```
!`python3 -c "exec('try:\n import yfinance, numpy, pandas\n print(\'YFIN_OK\')\nexcept Exception:\n print(\'YFIN_MISSING\')')"`
```

```
!`python3 -c "exec('try:\n import yfinance as yf\n t=yf.Ticker(\'^TNX\')\n p=t.fast_info.last_price\n print(f\'RF_10Y={p/100:.4f}\')\nexcept Exception:\n print(\'RF_FETCH_FAIL\')')"`
```

**Decision tree:**

| Condition | Method path |
|---|---|
| `YFIN_OK` | **Path A** (primary): yfinance for financials + peer multiples |
| `YFIN_MISSING` | **Path B**: pip-install yfinance, then Path A. `python3 -m pip install -q yfinance numpy pandas` |
| `RF_FETCH_FAIL` | Use default `rf = 0.045` and note stale risk-free rate in output |

If `RF_10Y=` printed, use that value as `rf` in Step 4d instead of the hardcoded 4.5%.

---

## Step 2: Choose Methods & Set Defaults

### Method applicability

| Company type | DCF | Relative | SOTP | Fallback |
|---|---|---|---|---|
| Mature cash-flow (CPG, telecom, utilities) | ✅ primary | ✅ | ❌ | — |
| High-growth SaaS / software | ✅ with care | ✅ primary | ❌ | Use EV/Revenue + Rule of 40 |
| Multi-segment conglomerate | ✅ | ✅ | ✅ primary | See `references/sotp.md` |
| Banks / insurance | ❌ | ✅ (P/B, P/TBV) | ❌ | DDM or excess return; note in output |
| Pre-revenue | ❌ | EV/Revenue only | ❌ | Flag low confidence |
| REITs | ❌ | ✅ (P/FFO, P/AFFO) | ❌ | NAV-based |
| Cyclicals (energy, semis, industrials) | ✅ on mid-cycle | ✅ | sometimes | Normalize through-cycle |

### Defaults table

Settle every parameter before pulling data — these defaults apply unless the user overrides them.

| Parameter | Default | Rationale |
|---|---|---|
| Projection horizon | 5 years | Standard explicit forecast window |
| Terminal growth `g` | 2.5% | ~ long-run US GDP |
| Risk-free rate `rf` | Live 10Y UST from Step 1, else 4.5% | Current cost of capital anchor |
| Equity risk premium `erp` | 5.5% | Damodaran mid-range |
| Beta | `info['beta']` from yfinance | Market-observed levered beta |
| Cost of debt `kd` | `interest_expense / total_debt`, else 5.5% | Effective rate; fallback to IG spread |
| Tax rate | 3-yr median effective rate, floored 15%, capped 30% | Strips out one-offs |
| Margin assumptions | 3-yr median of each ratio | Smooths cyclical noise |
| SBC treatment | Cash for software/SaaS; non-cash for industrials/CPG | Industry convention |
| Peer count | 4-6 | Balances signal vs noise |
| Peer multiple | Median (not mean) | Robust to outliers |
| Method weights (no SOTP) | DCF 50% / Relative 50% | Equal triangulation |
| Method weights (with SOTP) | DCF 40% / Relative 30% / SOTP 30% | SOTP gets weight when applicable |
| Sensitivity grid | WACC ±1% in 0.5% steps × g from 1.5-3.5% in 0.5% | 5×5 matrix |

See `references/wacc_erp_rates.md` for current risk-free rates, ERP tables, and sector WACC benchmarks.

---

## Step 3: Pull Data

```python
import yfinance as yf
import numpy as np
import pandas as pd

TICKER = "AAPL"  # replace
t = yf.Ticker(TICKER)

info       = t.info
income_a   = t.income_stmt
cashflow_a = t.cashflow
balance_a  = t.balance_sheet
income_q   = t.quarterly_income_stmt
cashflow_q = t.quarterly_cashflow

earnings_est = t.earnings_estimate
revenue_est  = t.revenue_estimate

price       = info.get("currentPrice") or info.get("regularMarketPrice")
market_cap  = info.get("marketCap")
shares_out  = info.get("sharesOutstanding")
total_debt  = info.get("totalDebt") or 0
cash        = info.get("totalCash") or 0
beta        = info.get("beta") or 1.0
sector      = info.get("sector")
industry    = info.get("industry")
```

Key financial statement rows (yfinance labels):

| Need | Row |
|---|---|
| Revenue | `Total Revenue` |
| EBIT | `Operating Income` |
| Net income | `Net Income` |
| D&A | `Depreciation And Amortization` (in cashflow) |
| CapEx | `Capital Expenditure` (negative) |
| ΔNWC | `Change In Working Capital` (cashflow) |
| SBC | `Stock Based Compensation` (cashflow) |

---

## Step 4: DCF Build

Full methodology + industry-specific tweaks in `references/dcf.md`. Quick skeleton:

```python
# 4a. Revenue growth path — fade from Y1 (consensus or hist CAGR) to terminal g
rev = income_a.loc["Total Revenue"].dropna().iloc[::-1].values  # yfinance columns are newest-first; reverse to oldest -> newest
hist_cagr = (rev[-1] / rev[0]) ** (1 / (len(rev)-1)) - 1
y1 = float(revenue_est.loc["+1y", "growth"]) if "+1y" in revenue_est.index else hist_cagr
g_terminal = 0.025
growth_path = np.linspace(y1, g_terminal + 0.01, 5)

# 4b. Margins — 3y median
ebit_margin = float((income_a.loc["Operating Income"] / income_a.loc["Total Revenue"]).iloc[:3].median())
da_pct      = float((cashflow_a.loc["Depreciation And Amortization"] / income_a.loc["Total Revenue"]).iloc[:3].median())
capex_pct   = float((cashflow_a.loc["Capital Expenditure"].abs() / income_a.loc["Total Revenue"]).iloc[:3].median())
nwc_pct     = float((cashflow_a.loc["Change In Working Capital"].abs() / income_a.loc["Total Revenue"]).iloc[:3].median())
eff_tax     = (income_a.loc["Tax Provision"] / income_a.loc["Pretax Income"]).iloc[:3].median()
tax_rate    = float(min(0.30, max(0.15, eff_tax))) if pd.notna(eff_tax) else 0.21  # 3y median effective, floored 15%, capped 30%

# 4c. FCFF per year
rev_t = [float(income_a.loc["Total Revenue"].iloc[0])]
fcff  = []
for g in growth_path:
    rev_t.append(rev_t[-1] * (1 + g))
    ebit = rev_t[-1] * ebit_margin
    nopat = ebit * (1 - tax_rate)
    fcff.append(nopat + rev_t[-1]*da_pct - rev_t[-1]*capex_pct - rev_t[-1]*nwc_pct)

# 4d. WACC
rf, erp, kd = 0.045, 0.055, 0.055  # override rf with live value from Step 1
ke = rf + beta * erp
e_v = market_cap / (market_cap + total_debt)
d_v = 1 - e_v
wacc = e_v*ke + d_v*kd*(1 - tax_rate)

# 4e. Terminal value — compute both, use midpoint
tv_gordon = fcff[-1] * (1 + g_terminal) / (wacc - g_terminal)
tv_exit   = (rev_t[-1] * ebit_margin + rev_t[-1] * da_pct) * 15  # peer median EV/EBITDA
tv_base   = 0.5 * (tv_gordon + tv_exit)

# 4f. Bridge to equity
pv_fcff = sum(f / (1+wacc)**(i+1) for i, f in enumerate(fcff))
pv_tv   = tv_base / (1+wacc)**5
ev      = pv_fcff + pv_tv
equity  = ev + cash - total_debt
implied_price_dcf = equity / shares_out
```

**Gates:** (a) if `wacc <= g_terminal` → stop, g too aggressive; (b) if `pv_tv / ev > 0.85` or `< 0.45` → flag and show both TV methods; (c) if `wacc` is outside the sector sanity band in `references/wacc_erp_rates.md` → note.

---

## Step 5: Relative Valuation

Select 4-6 peers. Peer map and adjustment rules in `references/relative_valuation.md`.

```python
PEERS = ["MSFT", "ORCL", "CRM", "NOW", "SAP", "WDAY"]  # pick by industry
multiples = {}
for p in PEERS:
    pi = yf.Ticker(p).info
    multiples[p] = {
        "pe_fwd": pi.get("forwardPE"),
        "ev_rev": pi.get("enterpriseToRevenue"),
        "ev_ebitda": pi.get("enterpriseToEbitda"),
        "ps": pi.get("priceToSalesTrailing12Months"),
    }
med_pe     = np.nanmedian([v["pe_fwd"] for v in multiples.values()])
med_ev_rev = np.nanmedian([v["ev_rev"] for v in multiples.values()])
med_ev_eb  = np.nanmedian([v["ev_ebitda"] for v in multiples.values()])

eps_ttm    = float(income_q.loc["Diluted EPS"].iloc[:4].sum())
rev_ttm    = float(income_q.loc["Total Revenue"].iloc[:4].sum())
ebitda_ttm = float(income_q.loc["EBIT"].iloc[:4].sum()) + float(cashflow_q.loc["Depreciation And Amortization"].iloc[:4].sum())
net_debt   = total_debt - cash

implied_pe       = med_pe * eps_ttm
implied_ev_rev   = (med_ev_rev * rev_ttm - net_debt) / shares_out
implied_ev_ebit  = (med_ev_eb  * ebitda_ttm - net_debt) / shares_out
implied_price_rel = np.nanmedian([implied_pe, implied_ev_rev, implied_ev_ebit])
```

Adjust peer median ±10-30% if target's growth or margin profile diverges materially. Always state the adjustment and reason. Rule of 40 anchor for SaaS in `references/relative_valuation.md`.

---

## Step 6: SOTP (multi-segment only)

Skip unless the 10-K reports 2+ operating segments with distinct economics. yfinance does NOT expose segment data — user must supply or parse from filings. Full methodology in `references/sotp.md`:
- Identify segments + pure-play peer for each
- Apply peer median EV/EBITDA (or EV/Rev for growth segments)
- Subtract unallocated corporate costs (cap 2-5% of revenue if unknown)
- Subtract net debt, minority interest; divide by shares

SOTP discount = (SOTP price − market price) / SOTP price. Flag if >20% (conglomerate discount).

---

## Step 7: Triangulate, Sensitivity, Scenarios

```python
# Blended implied price
if sotp_price is None:
    blended = 0.5*implied_price_dcf + 0.5*implied_price_rel
else:
    blended = 0.4*implied_price_dcf + 0.3*implied_price_rel + 0.3*sotp_price

# 5x5 sensitivity grid
wacc_grid = [wacc + dx for dx in (-0.01, -0.005, 0, 0.005, 0.01)]
g_grid    = [0.015, 0.020, 0.025, 0.030, 0.035]
sens = {}
for w in wacc_grid:
    for g in g_grid:
        tv = fcff[-1]*(1+g)/(w-g)
        pv = sum(f/(1+w)**(i+1) for i,f in enumerate(fcff)) + tv/(1+w)**5
        sens[(w,g)] = (pv + cash - total_debt) / shares_out
```

Also produce Bull / Base / Bear: shift revenue growth ±300bps, EBIT margin ±200bps, WACC ∓100bps, terminal g 3.0% / 2.5% / 1.5%.

---

## Step 8: Respond to the User

Present the valuation in this order:

1. **Headline verdict** — one sentence with the blended fair value, the current price, the % upside or downside, and which method is most bullish or bearish.
2. **Snapshot** — sector, industry, market cap, current price, 3M / 12M price change, LTM revenue growth.
3. **Three-method summary** — 3-column table: method | implied price | weight | brief rationale.
4. **DCF build** — assumptions table (growth path, margins, WACC components, terminal method) + 5-yr FCFF projection table + EV-to-equity bridge.
5. **Peer comparison** — table of peers with P/E fwd, EV/Rev, EV/EBITDA, gross margin, rev growth; bottom row = median; flag target's premium/discount.
6. **SOTP** (if applicable) — segment table + adjustments + equity value.
7. **Sensitivity matrix** — WACC × g grid (5×5), base case highlighted.
8. **Scenarios** — Bull / Base / Bear table with levers + implied price.
9. **Key risks** — which assumptions move the answer most, and what could break the thesis.

### Error handling

| Missing / edge case | Action |
|---|---|
| yfinance returns `None` for beta | Use sector-default beta from `references/wacc_erp_rates.md` |
| Negative LTM EBITDA | Skip EV/EBITDA multiple; rely on EV/Revenue + DCF |
| Negative LTM EPS | Skip P/E multiple; use forward P/E if positive, else skip |
| Growth > WACC in Gordon | Cap `g = wacc − 0.5%` and flag |
| Fewer than 3 years history | Use what's available; flag data confidence as "low" |
| Peer data fetch fails | Drop that peer from median; note in output |
| No segment data for SOTP | Skip Section 6; proceed with DCF + Relative only |

### Caveats to include
- TTM data lags real-time; peer multiples reflect market sentiment (can overshoot)
- DCF is garbage-in/garbage-out; sensitivity matters more than a point estimate
- yfinance data is unofficial; cross-check any decision with primary filings
- Not financial advice

---

## Reference Files

- `references/dcf.md` — DCF methodology + industry-specific guidance (software, retail, financials, healthcare, energy, manufacturing, CPG, telecom, REITs, streaming)
- `references/relative_valuation.md` — Peer selection, multiple adjustment rules, Rule of 40, peer sets by theme
- `references/sotp.md` — Sum-of-parts methodology, conglomerate discount detection, catalysts
- `references/wacc_erp_rates.md` — Risk-free rates, equity risk premiums, sector WACC benchmarks, sector-default betas

© himself65 · MIT · himself65/finance-skills

Similar skills

Everything for Finance and business →

From the same set22

etf-premium Works out whether an ETF trades above or below NAV using Yahoo Finance data, compares funds against each other, and breaks a sudden price jump into its causes. CX Codex +1 3,100installs stock-liquidity Evaluates stock liquidity via yfinance: bid-ask spreads, trading volume, and market impact. Helps gauge trading costs before entering or exiting positions. CX Codex +1 3,100installs estimate-analysis Pulls sell-side EPS and revenue estimates for a ticker from Yahoo Finance and shows how the consensus moved over the last 7, 30, 60 and 90 days. CX Codex +1 3,200installs hormuz-strait Pulls the Hormuz Strait Monitor dashboard and answers whether the strait is open, how many tankers got through, and what happened to Brent. CX Codex +1 3,200installs startup-analysis This skill reviews a startup as an investor, job applicant, and founder. Use it to assess a company, a job offer, or an investment case. CX Codex +1 3,000installs sepa-strategy Screens a stock the Minervini way: market stage, the 8-condition trend template, fundamentals, VCP base, and position size from your risk. CX Codex +1 3,000installs saas-valuation-compression Researches funding rounds for private SaaS companies and calculates round-to-round ARR valuation multiples. It attributes multiple compression to macro cycles, growth shifts, or AI premiums. CX Codex +1 2,900installs skill-creator A skill that walks you through creating a new agent skill, fixing one that misbehaves, or scoring it against a rubric. Useful when a manual routine should become repeatable. CX Codex +1 2,800installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor