jnachi
Learning Hub
Finance & FinOps AI8 min readAdvanced

Monte Carlo Risk Simulations & Valuation Sensitivity Matrices

Execute high-iteration probabilistic Monte Carlo simulations, generate Value-at-Risk (VaR) percentiles, and build dynamic 2-way sensitivity tables.

Works with:NumPySciPy StatsMatplotlib / SeabornPandas

Key Takeaways

  • Deterministic point estimates ("revenue will grow exactly 12%") fail to capture downside risk; Monte Carlo simulations model probability distributions
  • Running 10,000+ simulation iterations generates confidence intervals (P10, P50, P90) for target valuation and EBITDA
  • Value-at-Risk (VaR) calculates maximum expected portfolio loss at a 95% or 99% confidence level over a specific time horizon
  • 2-way sensitivity matrices display valuation outputs across varying discount rates (WACC) and terminal growth assumptions

The Diagnostic Context

Institutional investment committees do not make decisions on single-number projections. Monte Carlo simulations stress-test financial models across thousands of simulated economic scenarios to uncover probability distributions and tail risks.

The Core Technique

Running a 10,000-Iteration Monte Carlo Valuation in Python

PYTHON
import numpy as np

def run_monte_carlo_valuation(
    base_ebitda: float,
    mean_growth: float = 0.08,
    growth_std: float = 0.04,
    mean_multiple: float = 12.0,
    multiple_std: float = 1.5,
    iterations: int = 10000
) -> dict:
    # 1. Sample stochastic growth rates (Normal distribution)
    growth_samples = np.random.normal(mean_growth, growth_std, iterations)
    
    # 2. Sample stochastic EV/EBITDA exit multiples (Truncated distribution)
    multiple_samples = np.random.normal(mean_multiple, multiple_std, iterations)
    multiple_samples = np.clip(multiple_samples, 6.0, 25.0) # realistic floor/ceiling
    
    # 3. Calculate 5-year future EBITDA & Enterprise Value per iteration
    projected_ebitda = base_ebitda * ((1 + growth_samples) ** 5)
    simulated_ev = projected_ebitda * multiple_samples
    
    # 4. Extract Percentiles
    p10 = np.percentile(simulated_ev, 10) # Downside bear case
    p50 = np.percentile(simulated_ev, 50) # Base median case
    p90 = np.percentile(simulated_ev, 90) # Upside bull case
    
    return {
        "iterations": iterations,
        "p10_bear_valuation": round(float(p10), 2),
        "p50_median_valuation": round(float(p50), 2),
        "p90_bull_valuation": round(float(p90), 2),
        "mean_valuation": round(float(np.mean(simulated_ev)), 2),
        "std_deviation": round(float(np.std(simulated_ev)), 2)
    }

Generating 2-Way Sensitivity Tables

Sensitivity analysis evaluates how valuation changes when adjusting two key variables simultaneously (e.g. WACC from 8.0% to 12.0% on the vertical axis vs Terminal Growth from 1.5% to 3.5% on the horizontal axis).

5-Minute Activation Challenge

Try This Right Now

Run the Monte Carlo function with $100M base EBITDA. Compare how widening the growth standard deviation from 4% to 10% impacts the P10 downside valuation!

Tip: Knowledge only becomes capability once you run the prompt yourself.

Comprehension Check

Test Your Instincts (1 Questions)

1

What does a P10 valuation output of $450 Million represent in a Monte Carlo distribution?