himself65/finance-skills

company-valuation

Estimate 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.

Voir la source
Document Skill original

Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.

Company Valuation

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:

ConditionMethod path
YFIN_OKPath A (primary): yfinance for financials + peer multiples
YFIN_MISSINGPath B: pip-install yfinance, then Path A. python3 -m pip install -q yfinance numpy pandas
RF_FETCH_FAILUse 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 typeDCFRelativeSOTPFallback
Mature cash-flow (CPG, telecom, utilities)✅ primary
High-growth SaaS / software✅ with care✅ primaryUse EV/Revenue + Rule of 40
Multi-segment conglomerate✅ primarySee references/sotp.md
Banks / insurance✅ (P/B, P/TBV)DDM or excess return; note in output
Pre-revenueEV/Revenue onlyFlag low confidence
REITs✅ (P/FFO, P/AFFO)NAV-based
Cyclicals (energy, semis, industrials)✅ on mid-cyclesometimesNormalize through-cycle

Defaults table

Every parameter below MUST have a value before moving to Step 3. Use these unless the user overrides.

ParameterDefaultRationale
Projection horizon5 yearsStandard explicit forecast window
Terminal growth g2.5%~ long-run US GDP
Risk-free rate rfLive 10Y UST from Step 1, else 4.5%Current cost of capital anchor
Equity risk premium erp5.5%Damodaran mid-range
Betainfo['beta'] from yfinanceMarket-observed levered beta
Cost of debt kdinterest_expense / total_debt, else 5.5%Effective rate; fallback to IG spread
Tax rate3-yr median effective rate, floored 15%, capped 30%Strips out one-offs
Margin assumptions3-yr median of each ratioSmooths cyclical noise
SBC treatmentCash for software/SaaS; non-cash for industrials/CPGIndustry convention
Peer count4-6Balances signal vs noise
Peer multipleMedian (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 gridWACC ±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):

NeedRow
RevenueTotal Revenue
EBITOperating Income
Net incomeNet Income
D&ADepreciation And Amortization (in cashflow)
CapExCapital Expenditure (negative)
ΔNWCChange In Working Capital (cashflow)
SBCStock 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
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())
tax_rate    = max(0.15, min(0.30, 0.21))  # use effective if available

# 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

Output in this order:

  1. Headline verdict — one sentence: blended fair value, vs. current, % upside/downside, most bullish/bearish method. Example: "AAPL fair value ≈ $215 (blended), vs. current $198 → ~9% upside; DCF is most bullish at $228."
  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 — 3-5 bullets: which assumption moves the answer most; what could break the thesis.

Error handling

Missing / edge caseAction
yfinance returns None for betaUse sector-default beta from references/wacc_erp_rates.md
Negative LTM EBITDASkip EV/EBITDA multiple; rely on EV/Revenue + DCF
Negative LTM EPSSkip P/E multiple; use forward P/E if positive, else skip
Growth > WACC in GordonCap g = wacc − 0.5% and flag
Fewer than 3 years historyUse what's available; flag data confidence as "low"
Peer data fetch failsDrop that peer from median; note in output
No segment data for SOTPSkip 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
du même dépôt

Autres Skills

Tous les Skills
himself65
Communauté

earnings-preview

Generate a pre-earnings briefing for any stock using Yahoo Finance data. Use this skill whenever the user wants to prepare for an upcoming earnings report, understand what analysts expect, review a company's beat/miss track record, or get a quick overview before an earnings call. Triggers include: "earnings preview for AAPL", "what to expect from TSLA earnings", "MSFT reports next week", "earnings preview", "pre-earnings analysis", "what are analysts expecting for NVDA", "earnings estimates for", "will GOOGL beat earnings", "earnings beat/miss history", "upcoming earnings", "before earnings", "earnings setup", "consensus estimates", "earnings whisper", "EPS expectations", "what's the street expecting", "earnings season preview", any mention of preparing for or previewing an earnings report, or any request to understand expectations ahead of a company's earnings date. Always use this skill when the user mentions a ticker in context of upcoming earnings, even if they don't say "preview" explicitly.

installations
2
GitHub Stars
3,3 k
Mis à jour
27 août
himself65
Communauté

earnings-recap

Generate a post-earnings analysis for any stock using Yahoo Finance data. Use when the user wants to review what happened after earnings, understand beat/miss results, see stock reaction, or get an earnings recap. Triggers: "AAPL earnings recap", "how did TSLA earnings go", "MSFT earnings results", "did NVDA beat earnings", "post-earnings analysis", "earnings surprise", "what happened with GOOGL earnings", "earnings reaction", "stock moved after earnings", "EPS beat or miss", "revenue beat or miss", "quarterly results for", "how were earnings", "AMZN reported last night", "earnings call recap", or any request about a company's recent earnings outcome. Use this skill when the user references a past earnings event, even if they just say "AAPL reported" or "how did they do".

installations
2
GitHub Stars
3,3 k
Mis à jour
27 août
himself65
Communauté

estimate-analysis

Deep-dive into analyst estimates and revision trends for any stock using Yahoo Finance data. Use when the user wants to understand analyst estimate direction, how EPS or revenue forecasts changed over time, compare estimate distributions, or analyze growth projections across periods. Triggers: "estimate analysis for AAPL", "analyst estimate trends for NVDA", "EPS revisions for TSLA", "how have estimates changed for MSFT", "estimate revisions", "EPS trend", "revenue estimates", "consensus changes", "analyst estimates", "estimate distribution", "growth estimates for", "estimate momentum", "revision trend", "forward estimates", "next quarter estimates", "annual estimates", "estimate spread", "bull vs bear estimates", "estimate range", or any request about tracking or comparing analyst estimates/revisions. Use this skill when the user asks about estimates beyond a simple lookup — if they want context, trends, or analysis, this is the right skill.

installations
2
GitHub Stars
3,3 k
Mis à jour
27 août
himself65
Communauté

etf-premium

Calculate ETF premium/discount vs NAV via Yahoo Finance, and decompose single-day surges into NAV-driven vs structural components (gamma squeeze, dealer hedging, blocked AP arbitrage). Use whenever the user asks about an ETF's premium or discount, NAV comparison, why an ETF diverged from its holdings, or how much of a move is dealer-hedging-driven. Triggers: "ETF premium", "ETF discount", "NAV premium", "is SPY at a premium", "BITO premium", "IBIT premium", "bond ETF discount", "trading above/below NAV", "ETF premium screener", "biggest discount", "compare ETF NAV", "ETF arbitrage", "ETF gamma squeeze", "ETF premium surge", "decompose ETF move", "dealer gamma exposure", "GEX for ETF", "why did this ETF jump", "premium convergence", "AP arbitrage blocked", or any request about the gap between an ETF's price and underlying value. Especially relevant for leveraged, inverse, international, bond, commodity, and crypto ETFs.

installations
2
GitHub Stars
3,3 k
Mis à jour
27 août