Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    jgtolentino

    dcf-builder

    jgtolentino/dcf-builder
    Data & Analytics
    14

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Build defensible DCF models with cited sources, Excel export, and sensitivity analysis

    SKILL.md

    DCF Builder Skill

    Purpose

    Build discounted cash flow (DCF) models from SEC filings with full source attribution. Outputs Excel workbook with formulas and Markdown summary.

    Usage

    # Build DCF for Omnicom Group
    dcf = build_dcf(
        ticker_or_cik="OMC",
        currency="USD",
        scenario="base",
        forecast_years=5
    )
    

    Workflow

    1. Fetch Historical Financials

    def fetch_historical_financials(cik):
        """Fetch historical financials from SEC EDGAR"""
        # Get company facts (XBRL aggregated data)
        url = f"https://data.sec.gov/api/xbrl/companyfacts/CIK{cik.zfill(10)}.json"
        response = requests.get(url, headers=EDGAR_HEADERS, timeout=30)
        response.raise_for_status()
    
        facts = response.json()
    
        # Extract key metrics
        financials = {
            'revenue': extract_fact(facts, 'Revenues'),
            'cogs': extract_fact(facts, 'CostOfRevenue'),
            'operating_expenses': extract_fact(facts, 'OperatingExpenses'),
            'depreciation': extract_fact(facts, 'DepreciationAndAmortization'),
            'capex': extract_fact(facts, 'PaymentsToAcquirePropertyPlantAndEquipment'),
            'tax_rate': extract_fact(facts, 'EffectiveIncomeTaxRateContinuingOperations'),
            'cash': extract_fact(facts, 'Cash'),
            'debt': extract_fact(facts, 'LongTermDebt'),
            'shares_outstanding': extract_fact(facts, 'CommonStockSharesOutstanding'),
        }
    
        return financials
    
    def extract_fact(facts, concept_name):
        """Extract XBRL fact by concept name"""
        try:
            # Navigate nested structure: facts -> concept -> units -> values
            concept = facts['facts']['us-gaap'][concept_name]
            # Get USD annual values
            usd_values = concept['units']['USD']
            # Filter for 10-K filings (FY = full year)
            annual_values = [v for v in usd_values if v['form'] == '10-K']
            # Sort by date
            annual_values.sort(key=lambda x: x['end'], reverse=True)
            # Return most recent 5 years
            return [{
                'date': v['end'],
                'value': v['val'],
                'accession': v['accn'],
                'source': f"https://www.sec.gov/cgi-bin/viewer?action=view&cik={cik}&accession_number={v['accn']}"
            } for v in annual_values[:5]]
        except KeyError:
            return []
    

    2. Compute WACC

    def compute_wacc(cik, financials):
        """Compute Weighted Average Cost of Capital"""
    
        # Cost of Equity (CAPM): Rf + Beta * (Rm - Rf)
        risk_free_rate = 0.045  # 10-year Treasury yield
        market_risk_premium = 0.08  # Historical equity risk premium
        beta = fetch_beta(cik)  # From financial data providers or regression
    
        cost_of_equity = risk_free_rate + beta * market_risk_premium
    
        # Cost of Debt: Interest Expense / Total Debt
        interest_expense = extract_latest_value(financials, 'InterestExpense')
        total_debt = extract_latest_value(financials, 'LongTermDebt')
        cost_of_debt = interest_expense / total_debt if total_debt > 0 else 0.05
    
        # After-tax cost of debt
        tax_rate = extract_latest_value(financials, 'EffectiveIncomeTaxRateContinuingOperations') / 100
        cost_of_debt_after_tax = cost_of_debt * (1 - tax_rate)
    
        # Market values
        equity_value = extract_latest_value(financials, 'CommonStockSharesOutstanding') * fetch_stock_price(cik)
        debt_value = total_debt
    
        # WACC = (E/V) * Re + (D/V) * Rd * (1 - Tc)
        total_value = equity_value + debt_value
        wacc = (equity_value / total_value) * cost_of_equity + (debt_value / total_value) * cost_of_debt_after_tax
    
        return {
            'wacc': wacc,
            'cost_of_equity': cost_of_equity,
            'cost_of_debt': cost_of_debt_after_tax,
            'weights': {
                'equity': equity_value / total_value,
                'debt': debt_value / total_value,
            },
            'sources': {
                'risk_free_rate': '10-Year Treasury Yield',
                'beta': 'Computed from historical returns',
                'debt': financials['debt'][0]['source'],
            }
        }
    

    3. Forecast Free Cash Flow

    def forecast_fcf(financials, scenario='base', forecast_years=5):
        """Forecast Free Cash Flow"""
    
        # Historical revenue growth
        revenues = [f['value'] for f in financials['revenue']]
        historical_growth = [(revenues[i] / revenues[i+1]) - 1 for i in range(len(revenues)-1)]
        avg_growth = sum(historical_growth) / len(historical_growth)
    
        # Scenario assumptions
        growth_assumptions = {
            'base': avg_growth,
            'bull': avg_growth * 1.2,  # 20% higher
            'bear': avg_growth * 0.8,  # 20% lower
        }
    
        revenue_growth = growth_assumptions[scenario]
    
        # Forecast revenues
        latest_revenue = revenues[0]
        forecasted_revenues = []
        for year in range(1, forecast_years + 1):
            forecasted_revenue = latest_revenue * ((1 + revenue_growth) ** year)
            forecasted_revenues.append(forecasted_revenue)
    
        # Forecast FCF components
        fcf_projections = []
        for year, revenue in enumerate(forecasted_revenues, start=1):
            # Operating margin assumption (use historical average)
            ebitda_margin = compute_avg_margin(financials, 'EBITDA')
            ebitda = revenue * ebitda_margin
    
            # D&A as % of revenue
            da_pct = compute_avg_pct(financials, 'depreciation')
            depreciation = revenue * da_pct
    
            # EBIT = EBITDA - D&A
            ebit = ebitda - depreciation
    
            # Taxes
            tax_rate = extract_latest_value(financials, 'EffectiveIncomeTaxRateContinuingOperations') / 100
            taxes = ebit * tax_rate
    
            # NOPAT (Net Operating Profit After Tax)
            nopat = ebit - taxes
    
            # Add back D&A
            # Subtract Capex
            capex_pct = compute_avg_pct(financials, 'capex')
            capex = revenue * capex_pct
    
            # Change in NWC (working capital)
            nwc_change = revenue * 0.02  # Assume 2% of revenue growth
    
            # FCF = NOPAT + D&A - Capex - ΔNW C
            fcf = nopat + depreciation - capex - nwc_change
    
            fcf_projections.append({
                'year': year,
                'revenue': revenue,
                'ebitda': ebitda,
                'depreciation': depreciation,
                'ebit': ebit,
                'taxes': taxes,
                'nopat': nopat,
                'capex': capex,
                'nwc_change': nwc_change,
                'fcf': fcf,
            })
    
        return fcf_projections
    

    4. Calculate Terminal Value and Valuation

    def calculate_valuation(fcf_projections, wacc, terminal_growth=0.025):
        """Calculate enterprise and equity value"""
    
        # Discount FCF to present value
        pv_fcf = []
        for projection in fcf_projections:
            year = projection['year']
            fcf = projection['fcf']
            discount_factor = (1 + wacc) ** year
            pv = fcf / discount_factor
            pv_fcf.append(pv)
    
        sum_pv_fcf = sum(pv_fcf)
    
        # Terminal value (perpetuity growth method)
        final_fcf = fcf_projections[-1]['fcf']
        terminal_value = (final_fcf * (1 + terminal_growth)) / (wacc - terminal_growth)
    
        # Discount terminal value to present
        terminal_year = len(fcf_projections)
        pv_terminal_value = terminal_value / ((1 + wacc) ** terminal_year)
    
        # Enterprise value
        enterprise_value = sum_pv_fcf + pv_terminal_value
    
        # Equity value = EV - Net Debt
        net_debt = extract_latest_value(financials, 'LongTermDebt') - extract_latest_value(financials, 'Cash')
        equity_value = enterprise_value - net_debt
    
        # Price per share
        shares_outstanding = extract_latest_value(financials, 'CommonStockSharesOutstanding')
        price_target = equity_value / shares_outstanding
    
        return {
            'sum_pv_fcf': sum_pv_fcf,
            'terminal_value': terminal_value,
            'pv_terminal_value': pv_terminal_value,
            'enterprise_value': enterprise_value,
            'net_debt': net_debt,
            'equity_value': equity_value,
            'shares_outstanding': shares_outstanding,
            'price_target': price_target,
        }
    

    5. Sensitivity Analysis

    def sensitivity_analysis(fcf_projections, wacc, terminal_growth, financials):
        """Generate sensitivity table"""
    
        wacc_range = [wacc - 0.02, wacc - 0.01, wacc, wacc + 0.01, wacc + 0.02]  # ±200 bps
        tg_range = [terminal_growth - 0.01, terminal_growth - 0.005, terminal_growth,
                    terminal_growth + 0.005, terminal_growth + 0.01]  # ±100 bps
    
        sensitivity_table = []
        for w in wacc_range:
            row = []
            for tg in tg_range:
                valuation = calculate_valuation(fcf_projections, w, tg, financials)
                row.append(valuation['price_target'])
            sensitivity_table.append(row)
    
        return {
            'wacc_range': wacc_range,
            'terminal_growth_range': tg_range,
            'price_targets': sensitivity_table,
        }
    

    6. Export to Excel

    import openpyxl
    from openpyxl.styles import Font, Alignment
    
    def export_to_excel(dcf_model, filename='/exports/dcf_model.xlsx'):
        """Export DCF model to Excel with formulas"""
    
        wb = openpyxl.Workbook()
    
        # Historical sheet
        ws_hist = wb.active
        ws_hist.title = 'Historical'
        # ... populate historical data ...
    
        # Projections sheet
        ws_proj = wb.create_sheet('Projections')
        # ... populate projections with formulas ...
    
        # Valuation sheet
        ws_val = wb.create_sheet('Valuation')
        # ... populate valuation ...
    
        # Sensitivity sheet
        ws_sens = wb.create_sheet('Sensitivity')
        # ... populate sensitivity table ...
    
        # Sources sheet
        ws_sources = wb.create_sheet('Sources')
        ws_sources['A1'] = 'Data Sources'
        ws_sources['A1'].font = Font(bold=True, size=14)
    
        row = 3
        for metric, source in dcf_model['sources'].items():
            ws_sources[f'A{row}'] = metric
            ws_sources[f'B{row}'] = source
            row += 1
    
        wb.save(filename)
        return filename
    

    7. Generate Markdown Summary

    def generate_markdown_summary(dcf_model):
        """Generate Markdown summary with citations"""
    
        md = f"""
    # DCF Valuation: {dcf_model['ticker']}
    
    **Scenario**: {dcf_model['scenario']}
    **Date**: {datetime.now().strftime('%Y-%m-%d')}
    **Currency**: {dcf_model['currency']}
    
    ## Summary
    
    - **Enterprise Value**: {dcf_model['valuation']['enterprise_value']:,.0f}
    - **Equity Value**: {dcf_model['valuation']['equity_value']:,.0f}
    - **Price Target**: {dcf_model['valuation']['price_target']:.2f}
    
    ## Assumptions
    
    - **WACC**: {dcf_model['wacc']['wacc']:.2%}
    - **Terminal Growth**: {dcf_model['terminal_growth']:.2%}
    - **Forecast Period**: {dcf_model['forecast_years']} years
    
    ## Free Cash Flow Projections
    
    | Year | Revenue | EBITDA | FCF |
    |------|---------|--------|-----|
    """
    
        for proj in dcf_model['fcf_projections']:
            md += f"| {proj['year']} | {proj['revenue']:,.0f} | {proj['ebitda']:,.0f} | {proj['fcf']:,.0f} |\n"
    
        md += f"""
    ## Sensitivity Analysis
    
    Price target range: **{min(min(dcf_model['sensitivity']['price_targets']))} - {max(max(dcf_model['sensitivity']['price_targets'])):.2f}**
    
    ## Sources
    
    """
    
        for metric, source in dcf_model['sources'].items():
            md += f"- **{metric}**: {source}\n"
    
        md += """
    
    ---
    
    **Disclaimer**: This is an educational analysis and not investment advice.
    """
    
        return md
    

    Evaluation

    Test DCF output quality:

    # tests/finance/dcf-builder.yaml
    suite: dcf-builder
    thresholds:
      has_excel_export: true
      has_sensitivities: true
      cites_sources: true
    
    cases:
      - id: ev-dcf-omnicom
        prompt: "Build a base-case DCF for Omnicom (OMC) with 5y forecast"
        expects:
          - has_excel_export: true
          - has_formulas: true
          - has_sensitivity_table: true
          - cites_sources: true
          - price_target_reasonable: true  # Within 20% of current price
    

    References

    • DCF Methodology: https://www.investopedia.com/terms/d/dcf.asp
    • XBRL Facts API: https://www.sec.gov/edgar/sec-api-documentation
    • WACC Calculation: https://corporatefinanceinstitute.com/resources/valuation/wacc-formula/
    Recommended Servers
    LILT
    LILT
    InfraNodus Knowledge Graphs & Text Analysis
    InfraNodus Knowledge Graphs & Text Analysis
    Excel
    Excel
    Repository
    jgtolentino/insightpulse-odoo
    Files