Builds DCF models for equity valuation using SEC data, cash flow projections, WACC calculations, sensitivity analysis, and Excel outputs.
From financial-analysisnpx claudepluginhub anthropics/financial-services-plugins --plugin financial-analysisThis skill uses the workspace's default tool permissions.
TROUBLESHOOTING.mdrequirements.txtscripts/validate_dcf.pyDesigns and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
This skill creates institutional-quality DCF models for equity valuation following investment banking standards. Each analysis produces a detailed Excel model (with sensitivity analysis included at the bottom of the DCF sheet).
These constraints apply throughout all DCF model building. Review before starting:
Environment: Office JS vs Python/openpyxl:
range.formulas = [["=D19*(1+$B$8)"]]. No separate recalc step needed; Excel calculates natively. Use range.format.* for styling. The same formulas-over-hardcodes rule applies: set .formulas, never .values for derived cells.recalc.py before delivery.⚠️ Office JS merged cell pitfall: When building section headers with merged cells, do NOT call .merge() then set .values on the merged range — Office JS still reports the range's original dimensions and will throw InvalidArgument: The number of rows or columns in the input array doesn't match the size or dimensions of the range. Instead, write the value to the top-left cell alone, then merge and format the full range:
// WRONG — throws InvalidArgument:
const hdr = ws.getRange("A7:H7");
hdr.merge();
hdr.values = [["MARKET DATA & KEY INPUTS"]]; // 1×1 array vs 1×8 range → fails
// CORRECT — value first on single cell, then merge + format the range:
ws.getRange("A7").values = [["MARKET DATA & KEY INPUTS"]];
const hdr = ws.getRange("A7:H7");
hdr.merge();
hdr.format.fill.color = "#1F4E79";
hdr.format.font.bold = true;
hdr.format.font.color = "#FFFFFF";
This applies to every merged section header in the DCF (market data, scenario blocks, cash flow projection, terminal value, valuation summary, sensitivity tables).
Formulas Over Hardcodes (NON-NEGOTIABLE):
ws["D20"] = "=D19*(1+$B$8)" is correct; ws["D20"] = calculated_revenue is WRONGVerify Step-by-Step With the User (DO NOT build end-to-end):
Sensitivity Tables:
#BDD7EE) + bold font so it's immediately visible which cell is the base case.Cell Comments:
Model Layout Planning:
Formula Recalculation:
python recalc.py model.xlsx 30 before deliveryScenario Blocks:
=IF($B$6=1,[Bear cell],IF($B$6=2,[Base cell],[Bull cell]))Fetch data from MCP servers, user provided data, and the web.
Data Sources Priority:
Validation Checklist:
Analyze and document:
Create summary tables showing:
Historical Metrics (LTM):
Revenue: $X million
Revenue growth: X% CAGR
Gross margin: X%
EBIT margin: X%
D&A % of revenue: X%
CapEx % of revenue: X%
FCF margin: X%
Methodology:
Growth Rate Framework:
Formula structure:
Three-scenario approach:
Bear Case: Conservative growth (e.g., 8-12%)
Base Case: Most likely scenario (e.g., 12-16%)
Bull Case: Optimistic growth (e.g., 16-20%)
Fixed/Variable Cost Analysis:
Operating expenses should model realistic operating leverage:
Key principles:
Margin expansion framework:
Current State → Target State (Year 5)
Gross Margin: X% → Y% (justify based on scale, efficiency)
EBIT Margin: X% → Y% (result of revenue growth + opex leverage)
Build FCF in proper sequence:
EBIT
(-) Taxes (EBIT × Tax Rate)
= NOPAT (Net Operating Profit After Tax)
(+) D&A (non-cash expense, % of revenue)
(-) CapEx (% of revenue, typically 4-8%)
(-) Δ NWC (change in working capital)
= Unlevered Free Cash Flow
Working Capital Modeling:
Maintenance vs Growth CapEx:
CAPM Methodology for Cost of Equity:
Cost of Equity = Risk-Free Rate + Beta × Equity Risk Premium
Where:
- Risk-Free Rate = Current 10-Year Treasury Yield
- Beta = 5-year monthly stock beta vs market index
- Equity Risk Premium = 5.0-6.0% (market standard)
Cost of Debt Calculation:
After-Tax Cost of Debt = Pre-Tax Cost of Debt × (1 - Tax Rate)
Determine Pre-Tax Cost of Debt from:
- Credit rating (if available)
- Current yield on company bonds
- Interest expense / Total Debt from financials
Capital Structure Weights:
Market Value Equity = Current Stock Price × Shares Outstanding
Net Debt = Total Debt - Cash & Equivalents
Enterprise Value = Market Cap + Net Debt
Equity Weight = Market Cap / Enterprise Value
Debt Weight = Net Debt / Enterprise Value
WACC = (Cost of Equity × Equity Weight) + (After-Tax Cost of Debt × Debt Weight)
Special Cases:
Typical WACC Ranges:
Mid-Year Convention:
Present Value Calculation:
For each projection year:
PV of FCF = Unlevered FCF × Discount Factor
Example (Year 1):
FCF = $1,000
WACC = 10%
Period = 0.5
Discount Factor = 1 / (1.10)^0.5 = 0.9535
PV = $1,000 × 0.9535 = $954
Projection Period Selection:
Perpetuity Growth Method (Preferred):
Terminal FCF = Final Year FCF × (1 + Terminal Growth Rate)
Terminal Value = Terminal FCF / (WACC - Terminal Growth Rate)
Critical Constraint: Terminal Growth < WACC (otherwise infinite value)
Terminal Growth Rate Selection:
Do not exceed: Risk-free rate or long-term GDP growth
Exit Multiple Method (Alternative):
Terminal Value = Final Year EBITDA × Exit Multiple
Where Exit Multiple comes from:
- Industry comparable trading multiples
- Precedent transaction multiples
- Typical range: 8-15x EBITDA
Present Value of Terminal Value:
PV of Terminal Value = Terminal Value / (1 + WACC)^Final Period
Where Final Period accounts for timing:
5-year model with mid-year convention: Period = 4.5
Terminal Value Sanity Check:
Valuation Summary Structure:
(+) Sum of PV of Projected FCFs = $X million
(+) PV of Terminal Value = $Y million
= Enterprise Value = $Z million
(-) Net Debt [or + Net Cash if negative] = $A million
= Equity Value = $B million
÷ Diluted Shares Outstanding = C million shares
= Implied Price per Share = $XX.XX
Current Stock Price = $YY.YY
Implied Return = (Implied Price / Current Price) - 1 = XX%
Critical Adjustments:
Valuation Output Format:
Valuation Component,Amount ($M)
PV Explicit FCFs,X.X
PV Terminal Value,Y.Y
Enterprise Value,Z.Z
(-) Net Debt,A.A
Equity Value,B.B
,,
Shares Outstanding (M),C.C
Implied Price per Share,$XX.XX
Current Share Price,$YY.YY
Implied Upside/(Downside),+XX%
Build three sensitivity tables at the bottom of the DCF sheet showing how valuation changes with different assumptions:
Implementation: These are simple 2D grids (NOT Excel's "Data Table" feature) with formulas in each cell. Each cell must contain a full DCF recalculation for that specific assumption combination. See Critical Constraints section for detailed requirements on populating all 75 cells programmatically using openpyxl.
<correct_patterns>
This section contains all the CORRECT patterns to follow when building DCF models.
Assumptions are organized in separate blocks for each scenario:
CRITICAL STRUCTURE - Three rows per section header:
BEAR CASE ASSUMPTIONS (section header, merge cells across)
Assumption,FY1,FY2,FY3,FY4,FY5
Revenue Growth (%),12%,10%,9%,8%,7%
EBIT Margin (%),45%,44%,43%,42%,41%
BASE CASE ASSUMPTIONS (section header, merge cells across)
Assumption,FY1,FY2,FY3,FY4,FY5
Revenue Growth (%),16%,14%,12%,10%,9%
EBIT Margin (%),48%,49%,50%,51%,52%
BULL CASE ASSUMPTIONS (section header, merge cells across)
Assumption,FY1,FY2,FY3,FY4,FY5
Revenue Growth (%),20%,18%,15%,13%,11%
EBIT Margin (%),50%,51%,52%,53%,54%
Each scenario block MUST have a column header row showing the projection years (FY2025E, FY2026E, etc.) immediately below the section title. Without this, users cannot tell which assumption value corresponds to which year.
How to reference assumptions - Create a consolidation column:
Recommended consolidation column pattern (using INDEX):
=INDEX(B10:D10, 1, $B$6)
NOT this - scattered IF statements throughout:
=IF($B$6=1,[Bear block cell],IF($B$6=2,[Base block cell],[Bull block cell]))
The consolidation column approach centralizes logic and makes the model easier to audit.
Create a consolidation column with INDEX formulas, then reference it in projections:
Step 1 - Consolidation column for FY1 growth:
=INDEX([Bear FY1 growth]:[Bull FY1 growth], 1, $B$6)
Step 2 - Revenue projection references the consolidation column:
Revenue Year 1: =D29*(1+$E$10)
Where:
This approach is cleaner than embedding IF statements in every projection formula and makes it much easier to audit which scenario assumptions are being used.
Use consolidation columns with INDEX formulas, then reference them in FCF calculations:
Consolidation column approach:
Item,Formula,Reference
D&A,=E29*$E$21,$E$21 = consolidation column for D&A %
CapEx,=E29*$E$22,$E$22 = consolidation column for CapEx %
Δ NWC,=(E29-D29)*$E$23,$E$23 = consolidation column for NWC %
Unlevered FCF,=E57+E58-E60-E62,E57=NOPAT E58=D&A E60=CapEx E62=Δ NWC
Each consolidation column cell contains an INDEX formula that pulls from the appropriate scenario block based on case selector. This keeps projection formulas clean and auditable.
Before writing formulas, confirm scenario block row locations and set up consolidation columns.
Every hardcoded value needs this format:
"Source: [System/Document], [Date], [Reference], [URL if applicable]"
Examples:
Item,Source Comment
Stock price,Source: Market data script 2025-10-12 Close price
Shares outstanding,Source: 10-K FY2024 Page 45 Note 12
Historical revenue,Source: 10-K FY2024 Page 32 Consolidated Statements
Beta,Source: Market data script 2025-10-12 5-year monthly beta
Consensus estimates,Source: Management guidance Q3 2024 earnings call
CRITICAL: Each scenario block requires THREE structural elements:
Structure:
BEAR CASE ASSUMPTIONS (section header - merge across columns A:G)
Assumption,FY1,FY2,FY3,FY4,FY5
Revenue Growth (%),X%,X%,X%,X%,X%
EBIT Margin (%),X%,X%,X%,X%,X%
Terminal Growth,X%,,,,
WACC,X%,,,,
BASE CASE ASSUMPTIONS (section header - merge across columns A:G)
Assumption,FY1,FY2,FY3,FY4,FY5
Revenue Growth (%),X%,X%,X%,X%,X%
EBIT Margin (%),X%,X%,X%,X%,X%
Terminal Growth,X%,,,,
WACC,X%,,,,
BULL CASE ASSUMPTIONS (section header - merge across columns A:G)
Assumption,FY1,FY2,FY3,FY4,FY5
Revenue Growth (%),X%,X%,X%,X%,X%
EBIT Margin (%),X%,X%,X%,X%,X%
Terminal Growth,X%,,,,
WACC,X%,,,,
WITHOUT the column header row showing projection years (FY2025E, FY2026E, etc.), users cannot tell which assumption value corresponds to which year. This row is MANDATORY.
Then create a consolidation column (typically the next column to the right) that uses INDEX formulas to pull from the selected scenario block based on the case selector. This consolidation column is what your projection formulas reference.
1. Write ALL headers and labels FIRST:
Row,Content
1,[Company Name] DCF Model
2,Ticker | Date | Year End
4,Case Selector
7,KEY ASSUMPTIONS
26,Assumption headers
27-31,Growth assumptions
...,...
2. Write ALL section dividers and blank rows
3. THEN write formulas using the locked row positions
4. Test formulas immediately after creation
Think of it like construction:
Excel version:
IMPORTANT: These are NOT Excel's "Data Table" feature. These are simple grids where you write regular formulas using openpyxl. Yes, this means ~75 formulas total (3 tables × 25 cells each), but this is straightforward and required.
Programmatic Population with Formulas:
Each sensitivity table must be fully populated with formulas that recalculate the implied share price for each combination of assumptions. Do not use Excel's Data Table feature (it requires manual intervention and cannot be automated via openpyxl).
Implementation approach - CONCRETE EXAMPLE:
Table Structure — 5×5 grid (ODD dimensions, base case centered):
If the model's base WACC = 9.0% and base terminal growth = 3.0%, build the axes symmetrically around those values:
WACC vs Terminal Growth, 2.0%, 2.5%, 3.0%, 3.5%, 4.0%
8.0%, [fml], [fml], [fml], [fml], [fml]
8.5%, [fml], [fml], [fml], [fml], [fml]
9.0%, [fml], [fml], [★ ], [fml], [fml] ← middle row = base WACC
9.5%, [fml], [fml], [fml], [fml], [fml]
10.0%, [fml], [fml], [fml], [fml], [fml]
↑
middle col = base terminal g
★ = the center cell. Its formula output MUST equal the model's actual implied share price (from the valuation summary). Apply the medium-blue fill (#BDD7EE) and bold font to this cell so the base case is visually anchored.
Rule for axis values: axis_values = [base - 2*step, base - step, base, base + step, base + 2*step] — symmetric around the base, odd count guarantees a center.
Formula Pattern - Cell B88 (WACC=8.0%, Terminal Growth=2.0%):
The formula in B88 should recalculate the implied price using:
$A88 (8.0%)B$87 (2.0%)Recommended approach: Reference the main DCF calculation but substitute these values.
Example formula structure:
=([SUM of PV FCFs using $A88 as discount rate] + [Terminal Value using B$87 as growth rate and $A88 as WACC] - [Net Debt]) / [Shares]
CRITICAL - Write a formula for EVERY cell in the 5x5 grid (25 cells per table, 75 cells total). Use openpyxl to write these formulas programmatically in a loop. Do NOT skip this step or leave placeholder text.
Python implementation pattern:
# Pseudocode for populating sensitivity table
for row_idx, wacc_value in enumerate(wacc_range):
for col_idx, term_growth_value in enumerate(term_growth_range):
# Build formula that uses wacc_value and term_growth_value
formula = f"=<DCF recalc using {wacc_value} and {term_growth_value}>"
ws.cell(row=start_row+row_idx, column=start_col+col_idx).value = formula
The sensitivity tables must work immediately when the model is opened, with no manual steps required from the user.
</correct_patterns>
<common_mistakes>
This section contains all the WRONG patterns to avoid when building DCF models.
Don't use linear approximations:
// WRONG - Linear approximation
B97: =B88*(1+(0.096-0.116)) // Assumes linear relationship
// WRONG - Division shortcut
B105: =B88/(1+(E48-0.07)) // Doesn't recalculate full DCF
Don't leave placeholder text:
// WRONG - Placeholder note
"Note: Use Excel Data Table feature (Data → What-If Analysis → Data Table) to populate sensitivity tables."
// WRONG - Empty cells
[leaving cells blank because "this is complex"]
Don't confuse terminology:
Why these shortcuts are wrong:
Common rationalization to REJECT: "Writing 75+ formulas feels complex, so I'll leave a note for the user to complete it manually."
Reality: Writing 75 formulas is straightforward when you use a loop in Python with openpyxl. Each formula follows the same pattern - just substitute the row/column values. This is a required part of the deliverable.
Instead: Populate every sensitivity cell with formulas that recalculate the full DCF for that specific combination of assumptions
Don't do this:
Why it's wrong:
Instead: Add cell comment AS EACH hardcoded value is created
Symptom:
The FCF section references wrong assumption rows:
D&A: =E29*$E$34 // Should be $E$21, but referencing wrong row
CapEx: =E29*$E$41 // Should be $E$22, but row shifted
Why this happens:
Instead: Lock row layout FIRST, then write formulas
Don't structure assumptions like this:
Assumption,Bear,Base,Bull
Revenue Growth FY1,10%,13%,16%
Revenue Growth FY2,9%,12%,15%
This vertical layout makes it hard to see the progression across years within each scenario.
Why it's wrong:
Instead:
Don't deliver a model without borders:
Why it's wrong:
Instead: Add borders around all major sections
Don't do this:
Why it's wrong:
Instead: Blue text for ALL hardcoded inputs, black text for ALL formulas, green for sheet links
Don't do this:
S&M: =E33*0.15 // E33 = Gross Profit (WRONG)
Why it's wrong:
Instead:
S&M: =E29*0.15 // E29 = Revenue (CORRECT)
In addition, be aware of these errors:
These errors are the most common. Re-read this section before starting any DCF build.
</common_mistakes>
This skill uses the xlsx skill for all spreadsheet operations. The xlsx skill provides:
recalc.py scriptAll Excel files created by this skill must follow xlsx skill requirements, including zero formula errors and proper recalculation.
Every DCF model must maximize for:
Create two sheets:
CRITICAL: Sensitivity tables go at the BOTTOM of the DCF sheet (not on a separate sheet). This keeps all valuation outputs together.
After creating or modifying the Excel model, recalculate all formulas using the recalc.py script from the xlsx skill:
python recalc.py [path_to_excel_file] [timeout_seconds]
Example:
python recalc.py AAPL_DCF_Model_2025-10-12.xlsx 30
The script will:
Expected output format:
{
"status": "success", // or "errors_found"
"total_errors": 0, // Total error count
"total_formulas": 42, // Number of formulas in file
"error_summary": {} // Only present if errors found
}
If errors are found, the output will include details:
{
"status": "errors_found",
"total_errors": 2,
"total_formulas": 42,
"error_summary": {
"#REF!": {
"count": 2,
"locations": ["DCF!B25", "DCF!C25"]
}
}
}
Fix all errors and re-run recalc.py until status is "success" before delivering the model.
IMPORTANT: Follow the xlsx skill for formula construction rules and number formatting conventions. The DCF skill adds specific visual presentation standards.
Color Scheme - Two Layers:
Layer 1: Font Colors (MANDATORY from xlsx skill)
Layer 2: Fill Colors — Professional Blue/Grey Palette (Default unless user specifies otherwise)
#1F4E79) background with white bold text#D9E1F2) background with black bold text#F2F2F2) background with blue font — or just white with blue font if you want maximum minimalism#BDD7EE) background with black bold fontHow the layers work together:
Font color tells you WHAT it is (input/formula/link). Fill color tells you WHERE you are (header/data/output).
Thick borders (1.5pt) around major sections:
Medium borders (1pt) between sub-sections:
Thin borders (0.5pt) around data tables:
No borders: Individual cells within tables (keep clean, scannable)
Borders are mandatory - models without professional borders are not client-ready.
Number Formats (follows xlsx skill standards):
0.0% (one decimal place)$#,##0 for millions; $#,##0.00 for per-share - ALWAYS specify units in headers ("Revenue ($mm)")$#,##0;($#,##0);-)#,##0 with thousands separator(#,##0) in parentheses (NOT minus sign)Cell Comments (MANDATORY for all hardcoded inputs):
Per the xlsx skill, ALL hardcoded values must have cell comments documenting the source. Format: "Source: [System/Document], [Date], [Reference], [URL if applicable]"
CRITICAL: Add comments AS CELLS ARE CREATED. Do not defer to the end.
Section 1: Header
Row,Content
1,[Company Name] DCF Model
2,Ticker: [XXX] | Date: [Date] | Year End: [FYE]
3,Blank
4,Case Selector Cell (1=Bear 2=Base 3=Bull)
5,Case Name Display (formula: =IF([Selector]=1"Bear"IF([Selector]=2"Base""Bull")))
Section 2: Market Data (NOT case dependent)
Item,Value
Current Stock Price,$XX.XX
Shares Outstanding (M),XX.X
Market Cap ($M),[Formula]
Net Debt ($M),XXX [or Net Cash if negative]
Section 3: DCF Scenario Assumptions
Create separate assumption blocks for each scenario (Bear, Base, Bull) with DCF-specific assumptions (Revenue Growth %, EBIT Margin %, Tax Rate %, D&A % of Revenue, CapEx % of Revenue, NWC Change % of ΔRev, Terminal Growth Rate, WACC) laid out horizontally across projection years. Each block must include section header, column header row showing the projection years (FY1, FY2, etc.), and data rows. See <correct_patterns> section "Correct Assumption Table Structure" for the exact layout.
Section 4: Historical & Projected Financials
Reference a consolidation column (e.g., "Selected Case") that pulls from scenario blocks, not scattered IF formulas in every projection row.
Income Statement ($M),2020A,2021A,2022A,2023A,2024E,2025E,2026E
Revenue,XXX,XXX,XXX,XXX,[=E29*(1+$E$10)],[=F29*(1+$E$11)],[=G29*(1+$E$12)]
% growth,XX%,XX%,XX%,XX%,[=E29/D29-1],[=F29/E29-1],[=G29/F29-1]
,,,,,,
Gross Profit,XXX,XXX,XXX,XXX,[=E29*E33],[=F29*F33],[=G29*G33]
% margin,XX%,XX%,XX%,XX%,[=E33/E29],[=F33/F29],[=G33/G29]
,,,,,,
Operating Expenses:,,,,,,,
S&M,XXX,XXX,XXX,XXX,[=E29*0.15],[=F29*0.14],[=G29*0.13]
R&D,XXX,XXX,XXX,XXX,[=E29*0.12],[=F29*0.11],[=G29*0.10]
G&A,XXX,XXX,XXX,XXX,[=E29*0.08],[=F29*0.07],[=G29*0.07]
Total OpEx,XXX,XXX,XXX,XXX,[=E36+E37+E38],[=F36+F37+F38],[=G36+G37+G38]
,,,,,,
EBIT,XXX,XXX,XXX,XXX,[=E33-E39],[=F33-F39],[=G33-G39]
% margin,XX%,XX%,XX%,XX%,[=E41/E29],[=F41/F29],[=G41/G29]
,,,,,,
Taxes,(XX),(XX),(XX),(XX),[=E41*$E$24],[=F41*$E$24],[=G41*$E$24]
Tax rate,XX%,XX%,XX%,XX%,[=E43/E41],[=F43/F41],[=G43/G41]
,,,,,,
NOPAT,XXX,XXX,XXX,XXX,[=E41-E43],[=F41-F43],[=G41-G43]
Key Formula Pattern:
=E29*(1+$E$10) where $E$10 is consolidation column for Year 1 growth=E29*(1+IF($B$6=1,$B$10,IF($B$6=2,$C$10,$D$10)))This approach is cleaner, easier to audit, and prevents formula errors by centralizing the scenario logic.
Section 5: Free Cash Flow Build
CRITICAL: Verify row references point to the CORRECT assumption rows. Test formulas immediately after creation.
Cash Flow ($M),2020A,2021A,2022A,2023A,2024E,2025E,2026E
NOPAT,XXX,XXX,XXX,XXX,[=E45],[=F45],[=G45]
(+) D&A,XXX,XXX,XXX,XXX,[=E29*$E$21],[=F29*$E$21],[=G29*$E$21]
% of Rev,XX%,XX%,XX%,XX%,[=E58/E29],[=F58/F29],[=G58/G29]
(-) CapEx,(XX),(XX),(XX),(XX),[=E29*$E$22],[=F29*$E$22],[=G29*$E$22]
% of Rev,XX%,XX%,XX%,XX%,[=E60/E29],[=F60/F29],[=G60/G29]
(-) Δ NWC,(XX),(XX),(XX),(XX),[=(E29-D29)*$E$23],[=(F29-E29)*$E$23],[=(G29-F29)*$E$23]
% of Δ Rev,XX%,XX%,XX%,XX%,[=E62/(E29-D29)],[=F62/(F29-E29)],[=G62/(G29-F29)]
,,,,,,
Unlevered FCF,XXX,XXX,XXX,XXX,[=E57+E58-E60-E62],[=F57+F58-F60-F62],[=G57+G58-G60-G62]
Row reference examples (based on layout planning):
Before writing formulas: Confirm these row numbers match the actual layout. Test one column, then copy across.
Section 6: Discounting & Valuation
DCF Valuation,2024E,2025E,2026E,2027E,2028E,Terminal
Unlevered FCF ($M),XXX,XXX,XXX,XXX,XXX,
Period,0.5,1.5,2.5,3.5,4.5,
Discount Factor,0.XX,0.XX,0.XX,0.XX,0.XX,
PV of FCF ($M),XXX,XXX,XXX,XXX,XXX,
,,,,,,
Terminal FCF ($M),,,,,,,XXX
Terminal Value ($M),,,,,,,XXX
PV Terminal Value ($M),,,,,,,XXX
,,,,,,
Valuation Summary ($M),,,,,,
Sum of PV FCFs,XXX,,,,,
PV Terminal Value,XXX,,,,,
Enterprise Value,XXX,,,,,
(-) Net Debt,(XX),,,,,
Equity Value,XXX,,,,,
,,,,,,
Shares Outstanding (M),XX.X,,,,,
IMPLIED PRICE PER SHARE,$XX.XX,,,,,
Current Stock Price,$XX.XX,,,,,
Implied Upside/(Downside),XX%,,,,,
COST OF EQUITY CALCULATION,,
Risk-Free Rate (10Y Treasury),X.XX%,[Yellow input]
Beta (5Y monthly),X.XX,[Yellow input]
Equity Risk Premium,X.XX%,[Yellow input]
Cost of Equity,X.XX%,[Calculated blue]
,,
COST OF DEBT CALCULATION,,
Credit Rating,AA-,[Yellow input]
Pre-Tax Cost of Debt,X.XX%,[Yellow input]
Tax Rate,XX.X%,[Link to DCF sheet]
After-Tax Cost of Debt,X.XX%,[Calculated blue]
,,
CAPITAL STRUCTURE,,
Current Stock Price,$XX.XX,[Link to DCF]
Shares Outstanding (M),XX.X,[Link to DCF]
Market Capitalization ($M),"X,XXX",[Calculated]
,,
Total Debt ($M),XXX,[Yellow input]
Cash & Equivalents ($M),XXX,[Yellow input]
Net Debt ($M),XXX,[Calculated]
,,
Enterprise Value ($M),"X,XXX",[Calculated]
,,
WACC CALCULATION,Weight,Cost,Contribution
Equity,XX.X%,X.X%,X.XX%
Debt,XX.X%,X.X%,X.XX%
,,
WEIGHTED AVERAGE COST OF CAPITAL,X.XX%,[Green output]
Key WACC Formulas:
Market Cap = Price × Shares
Net Debt = Total Debt - Cash
Enterprise Value = Market Cap + Net Debt
Equity Weight = Market Cap / EV
Debt Weight = Net Debt / EV
WACC = (Cost of Equity × Equity Weight) + (After-tax Cost of Debt × Debt Weight)
TERMINOLOGY REMINDER: "Sensitivity tables" = simple 2D grids with row headers, column headers, and formulas in each data cell. NOT Excel's "Data Table" feature (Data → What-If Analysis → Data Table). You will use openpyxl to write regular Excel formulas into each cell.
Location: Rows 87+ on DCF sheet (NOT a separate sheet)
Three sensitivity tables, vertically stacked:
Total formulas to write: 75 (this is required, not optional)
CRITICAL: All sensitivity table cells must be populated programmatically with formulas using openpyxl. DO NOT use linear approximation shortcuts. DO NOT leave placeholder text or notes about manual steps. DO NOT rationalize leaving cells empty because "it's complex" - use a Python loop to generate the formulas.
Table Setup:
No manual intervention required - the sensitivity tables must be fully functional when the user opens the file.
Three-Case Framework:
Formula Implementation:
DO NOT use nested IF formulas scattered throughout. Instead, create a consolidation column that uses INDEX or OFFSET formulas to pull from the appropriate scenario block.
Recommended pattern (using INDEX):
=INDEX(B10:D10, 1, $B$6) where B10:D10 = Bear/Base/Bull values, 1 = row offset, $B$6 = case selector cell (1, 2, or 3)
Then reference the consolidation column in all projections:
Revenue Year 1: =D29*(1+$E$10) where $E$10 is the consolidation column value for Year 1 growth.
This approach centralizes scenario logic, making the model easier to audit and maintain.
File naming: [Ticker]_DCF_Model_[Date].xlsx
Two sheets:
Key features: Case selector (1/2/3), consolidation column with INDEX/OFFSET formulas, color-coded cells, cell comments on all inputs, professional borders
If you encounter errors or unreasonable results, read TROUBLESHOOTING.md for detailed debugging guidance.
Gather market data:
Gather historical financials:
Begin model construction using the DCF methodology detailed in this skill
Verify structure:
Recalculate formulas: Run python recalc.py model.xlsx 30
Check output:
status is "success" → Continue to step 4status is "errors_found" → Check error_summary and read TROUBLESHOOTING.md for debugging guidanceFix errors and re-run recalc.py until status is "success"
Spot-check formulas:
Deliver model
Before delivering DCF model:
Required:
python recalc.py model.xlsx 30 until status is "success" (zero formula errors)Validation:
[Ticker]_DCF_Model_[Date].xlsx