$npx -y skills add himself65/finance-skills --skill company-valuationEstimate the intrinsic value of a public company using DCF, relative (peer multiple) and sum-of-parts (SOTP) methods, then triangulate to an implied share price with upside/downside versus the current market price. Use this skill whenever the user asks: "what is AAPL worth", "val
| 1 | # Company Valuation |
| 2 | |
| 3 | Triangulates intrinsic value via three methods, then blends them to an implied share price: |
| 4 | |
| 5 | 1. **DCF** — 5-year FCFF projection, discount at WACC, terminal value. |
| 6 | 2. **Relative** — apply peer median P/E, EV/Revenue, EV/EBITDA. |
| 7 | 3. **SOTP** — when 2+ distinct reporting segments exist, value each at pure-play peer multiples. |
| 8 | |
| 9 | Always present a WACC × terminal-growth sensitivity table and Bull/Base/Bear scenarios. |
| 10 | |
| 11 | **Disclaimer**: Research/educational output. Not financial advice. |
| 12 | |
| 13 | --- |
| 14 | |
| 15 | ## Step 1: Detection Flow |
| 16 | |
| 17 | Detect data source and runtime deps. The skill supports 3 method paths — pick the richest one available. |
| 18 | |
| 19 | **Environment status:** |
| 20 | |
| 21 | ``` |
| 22 | !`python3 -c "import yfinance, numpy, pandas; print('YFIN_OK')" 2>/dev/null || echo "YFIN_MISSING"` |
| 23 | ``` |
| 24 | |
| 25 | ``` |
| 26 | !`(command -v funda && funda --version) 2>/dev/null || echo "FUNDA_CLI_MISSING"` |
| 27 | ``` |
| 28 | |
| 29 | ``` |
| 30 | !`python3 -c "import yfinance as yf; t=yf.Ticker('^TNX'); p=t.fast_info.last_price; print(f'RF_10Y={p/100:.4f}')" 2>/dev/null || echo "RF_FETCH_FAIL"` |
| 31 | ``` |
| 32 | |
| 33 | **Decision tree:** |
| 34 | |
| 35 | | Condition | Method path | |
| 36 | |---|---| |
| 37 | | `YFIN_OK` | **Path A** (primary): yfinance for financials + peer multiples | |
| 38 | | `YFIN_MISSING` but `FUNDA_CLI_MISSING` is not set | **Path B**: delegate to `finance-data-providers:funda-data` skill for fundamentals | |
| 39 | | Both missing | **Path C**: pip-install yfinance, then Path A. `python3 -m pip install -q yfinance numpy pandas` | |
| 40 | | `RF_FETCH_FAIL` | Use default `rf = 0.045` and note stale risk-free rate in output | |
| 41 | |
| 42 | If `RF_10Y=` printed, use that value as `rf` in Step 4d instead of the hardcoded 4.5%. |
| 43 | |
| 44 | --- |
| 45 | |
| 46 | ## Step 2: Choose Methods & Set Defaults |
| 47 | |
| 48 | ### Method applicability |
| 49 | |
| 50 | | Company type | DCF | Relative | SOTP | Fallback | |
| 51 | |---|---|---|---|---| |
| 52 | | Mature cash-flow (CPG, telecom, utilities) | ✅ primary | ✅ | ❌ | — | |
| 53 | | High-growth SaaS / software | ✅ with care | ✅ primary | ❌ | Use EV/Revenue + Rule of 40 | |
| 54 | | Multi-segment conglomerate | ✅ | ✅ | ✅ primary | See `references/sotp.md` | |
| 55 | | Banks / insurance | ❌ | ✅ (P/B, P/TBV) | ❌ | DDM or excess return; note in output | |
| 56 | | Pre-revenue | ❌ | EV/Revenue only | ❌ | Flag low confidence | |
| 57 | | REITs | ❌ | ✅ (P/FFO, P/AFFO) | ❌ | NAV-based | |
| 58 | | Cyclicals (energy, semis, industrials) | ✅ on mid-cycle | ✅ | sometimes | Normalize through-cycle | |
| 59 | |
| 60 | ### Defaults table |
| 61 | |
| 62 | Every parameter below MUST have a value before moving to Step 3. Use these unless the user overrides. |
| 63 | |
| 64 | | Parameter | Default | Rationale | |
| 65 | |---|---|---| |
| 66 | | Projection horizon | 5 years | Standard explicit forecast window | |
| 67 | | Terminal growth `g` | 2.5% | ~ long-run US GDP | |
| 68 | | Risk-free rate `rf` | Live 10Y UST from Step 1, else 4.5% | Current cost of capital anchor | |
| 69 | | Equity risk premium `erp` | 5.5% | Damodaran mid-range | |
| 70 | | Beta | `info['beta']` from yfinance | Market-observed levered beta | |
| 71 | | Cost of debt `kd` | `interest_expense / total_debt`, else 5.5% | Effective rate; fallback to IG spread | |
| 72 | | Tax rate | 3-yr median effective rate, floored 15%, capped 30% | Strips out one-offs | |
| 73 | | Margin assumptions | 3-yr median of each ratio | Smooths cyclical noise | |
| 74 | | SBC treatment | Cash for software/SaaS; non-cash for industrials/CPG | Industry convention | |
| 75 | | Peer count | 4-6 | Balances signal vs noise | |
| 76 | | Peer multiple | Median (not mean) | Robust to outliers | |
| 77 | | Method weights (no SOTP) | DCF 50% / Relative 50% | Equal triangulation | |
| 78 | | Method weights (with SOTP) | DCF 40% / Relative 30% / SOTP 30% | SOTP gets weight when applicable | |
| 79 | | Sensitivity grid | WACC ±1% in 0.5% steps × g from 1.5-3.5% in 0.5% | 5×5 matrix | |
| 80 | |
| 81 | See `references/wacc_erp_rates.md` for current risk-free rates, ERP tables, and sector WACC benchmarks. |
| 82 | |
| 83 | --- |
| 84 | |
| 85 | ## Step 3: Pull Data |
| 86 | |
| 87 | ```python |
| 88 | import yfinance as yf |
| 89 | import numpy as np |
| 90 | import pandas as pd |
| 91 | |
| 92 | TICKER = "AAPL" # replace |
| 93 | t = yf.Ticker(TICKER) |
| 94 | |
| 95 | info = t.info |
| 96 | income_a = t.income_stmt |
| 97 | cashflow_a = t.cashflow |
| 98 | balance_a = t.balance_sheet |
| 99 | income_q = t.quarterly_income_stmt |
| 100 | cashflow_q = t.quarterly_ |