Leveraged Buyout (LBO) Model Generator
1. Assumptions
Acquisition Details
Debt Tranche 1 (Senior Debt)
Operating Projections
Exit Assumptions
2. Debt Schedule
Calculate the model to see the debt schedule.
3. Summary & Valuation
Total Sources:
Total Uses:
Equity Contribution:
Entry EBITDA:
Exit EBITDA:
Exit Enterprise Value:
Net Debt at Exit:
Equity Value at Exit:
Multiple on Invested Capital (MOIC):
Internal Rate of Return (IRR):
Please fix input errors to see the summary results.
'; return; } // 2. Sources and Uses of Funds const totalUses = purchasePrice + transactionFees; const debtFinancingAmount = totalUses * debtPercentage; const equityContribution = totalUses - debtFinancingAmount; const totalSources = debtFinancingAmount + equityContribution; // Simple initial EBITDA for demonstration (assume 10% of purchase price for calculation starter) const entryEBITDA = purchasePrice * 0.15; // A reasonable starting point for model // 3. Operating Projections & Cash Flow Available for Debt Service (CFADS) const operatingData = []; let currentRevenue = purchasePrice / 2; // Arbitrary starting revenue related to purchase price let currentEBITDA = entryEBITDA; // Simplified CFADS calculation // For a basic model, let's assume CFADS is derived from EBITDA after some adjustments. // Here, we'll simply use EBITDA as a proxy for cash available for debt service, // or perhaps a fixed percentage of EBITDA, to keep it simple. // Let's assume CFADS = 80% of EBITDA for simplicity (adjust for taxes, capex, NWC later) const cfadsRatio = 0.8; for (let i = 0; i < projectionYears; i++) { const year = i + 1; if (i > 0) { currentRevenue *= (1 + revenueGrowth); currentEBITDA = currentRevenue * ebitdaMargin; } const cfads = currentEBITDA * cfadsRatio; // Simplified operatingData.push({ year: year, revenue: currentRevenue, ebitda: currentEBITDA, cfads: cfads }); } // 4. Debt Schedule (Tranche 1 only for simplicity) const debtSchedule = []; let beginningDebtBalance = debtFinancingAmount; let totalInterestPaid = 0; let totalPrincipalPaid = 0; for (let i = 0; i < debt1Term; i++) { const year = i + 1; if (beginningDebtBalance <= 0) { // If debt is paid off, stop debtSchedule.push({ year: year, beginningBalance: 0, interestPayment: 0, principalPayment: 0, endingBalance: 0 }); continue; } const interestPayment = beginningDebtBalance * debt1InterestRate; let principalPayment = beginningDebtBalance * debt1Amortization; // Ensure principal payment doesn't exceed remaining balance if (principalPayment > beginningDebtBalance) { principalPayment = beginningDebtBalance; } const endingBalance = beginningDebtBalance - principalPayment; debtSchedule.push({ year: year, beginningBalance: beginningDebtBalance, interestPayment: interestPayment, principalPayment: principalPayment, endingBalance: endingBalance }); beginningDebtBalance = endingBalance; totalInterestPaid += interestPayment; totalPrincipalPaid += principalPayment; } // If debt term is shorter than projection years, carry over remaining debt let netDebtAtExit = beginningDebtBalance; // Remaining balance after debt term if (projectionYears > debt1Term && netDebtAtExit > 0) { // For years beyond debt term but within projection years, debt remains constant for (let i = debt1Term; i < projectionYears; i++) { debtSchedule.push({ year: i + 1, beginningBalance: netDebtAtExit, interestPayment: 0, // Assuming no further interest if term ends, or fixed interest if it's balloon principalPayment: 0, endingBalance: netDebtAtExit }); } } // 5. Valuation & Returns const exitYearEBITDA = operatingData[projectionYears - 1].ebitda; const exitEnterpriseValue = exitYearEBITDA * exitMultiple; // Net debt at exit is the final balance of debt from the debt schedule netDebtAtExit = debtSchedule[projectionYears - 1] ? debtSchedule[projectionYears - 1].endingBalance : 0; if (netDebtAtExit < 0) netDebtAtExit = 0; // Cannot have negative debt const equityValueAtExit = exitEnterpriseValue - netDebtAtExit; const moic = equityValueAtExit / equityContribution; // IRR calculation (simplified) // For a basic LBO, cash flows are: // Year 0: -Equity Contribution // Year 'projectionYears': +Equity Value at Exit // Using a simple approximation for IRR, or a more robust XIRR if a library was used. // Here, we'll use a simplified iterative approach if possible, or a direct formula for 2 cash flows. // For 2 cash flows: (Equity Value at Exit / Equity Contribution)^(1/Projection Years) - 1 let irr = 0; if (equityContribution > 0) { // Newton-Raphson method for IRR (approximation for non-annual cash flows) // This is a simplified IRR for a single inflow/outflow const cashFlows = [-equityContribution]; for (let i = 0; i < projectionYears - 1; i++) { cashFlows.push(0); // Intermediate zero cash flows } cashFlows.push(equityValueAtExit); irr = calculateIRR(cashFlows); } else { showMessage('Equity Contribution is zero, IRR cannot be calculated.', 'info'); } // 6. Store results for display and PDF window.lboResults = { inputs: { purchasePrice, debtPercentage, transactionFees, debt1InterestRate, debt1Term, debt1Amortization, projectionYears, revenueGrowth, ebitdaMargin, exitMultiple }, financialSummary: { totalSources, totalUses, equityContribution, entryEBITDA, exitYearEBITDA, exitEnterpriseValue, netDebtAtExit, equityValueAtExit, moic, irr }, operatingData: operatingData, // Store operating data debtSchedule: debtSchedule }; // 7. Update UI displaySummaryResults(window.lboResults.financialSummary); displayDebtSchedule(window.lboResults.debtSchedule); // Optionally navigate to summary tab after calculation openTab('summary'); showMessage('LBO Model calculated successfully!', 'success'); } /** * Displays the LBO summary results in the UI. * @param {object} results The financial summary results object. */ function displaySummaryResults(results) { totalSourcesOutput.textContent = formatCurrency(results.totalSources); totalUsesOutput.textContent = formatCurrency(results.totalUses); equityContributionOutput.textContent = formatCurrency(results.equityContribution); entryEBITDAOutput.textContent = formatCurrency(results.entryEBITDA); exitEBITDAOutput.textContent = formatCurrency(results.exitYearEBITDA); exitEVOutput.textContent = formatCurrency(results.exitEnterpriseValue); netDebtAtExitOutput.textContent = formatCurrency(results.netDebtAtExit); equityValueAtExitOutput.textContent = formatCurrency(results.equityValueAtExit); moicOutput.textContent = results.moic.toFixed(2); irrOutput.textContent = formatPercentage(results.irr); } /** * Displays the debt schedule in a table format. * @param {Array} debtSchedule The array containing debt schedule data. */ function displayDebtSchedule(debtSchedule) { let tableHtml = `| Year | Beginning Balance | Interest Payment | Principal Payment | Ending Balance |
|---|---|---|---|---|
| ${row.year} | ${formatCurrency(row.beginningBalance)} | ${formatCurrency(row.interestPayment)} | ${formatCurrency(row.principalPayment)} | ${formatCurrency(row.endingBalance)} |
Calculate the model to see the debt schedule.
'; totalSourcesOutput.textContent = ''; totalUsesOutput.textContent = ''; equityContributionOutput.textContent = ''; entryEBITDAOutput.textContent = ''; exitEBITDAOutput.textContent = ''; exitEVOutput.textContent = ''; netDebtAtExitOutput.textContent = ''; equityValueAtExitOutput.textContent = ''; moicOutput.textContent = ''; irrOutput.textContent = ''; // Reset to the first tab openTab('inputs'); hideMessage(); } /** * Downloads the LBO model results as a PDF. */ function downloadPDF() { if (!window.lboResults) { showMessage('Please calculate the LBO model first.', 'info'); return; } const { jsPDF } = window.jspdf; const pdf = new jsPDF('p', 'mm', 'a4'); // 'p' for portrait, 'mm' for millimeters, 'a4' size const BLACK_COLOR = [31, 41, 55]; // Tailwind gray-900 equivalent const BLUE_HEADER_COLOR = [29, 78, 216]; // Tailwind blue-700 equivalent const RED_COLOR = [220, 38, 38]; // Tailwind red-600 equivalent const BLUE_TEXT_COLOR = [37, 99, 235]; // Tailwind blue-600 equivalent const GREEN_TEXT_COLOR = [22, 163, 74]; // Tailwind green-600 equivalent const GRAY_TEXT_COLOR = [75, 85, 99]; // Tailwind gray-700 equivalent let y = 15; // Y-coordinate for placing content // Title pdf.setFontSize(22); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(BLACK_COLOR[0], BLACK_COLOR[1], BLACK_COLOR[2]); pdf.text('Leveraged Buyout (LBO) Model Results', 105, y, { align: 'center' }); y += 15; // --- Input Parameters Section --- pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.text('1. Input Parameters', 15, y); y += 8; const inputData = [ ['Purchase Price', formatCurrency(window.lboResults.inputs.purchasePrice)], ['Debt Financing', `${window.lboResults.inputs.debtPercentage * 100}%`], ['Transaction Fees', formatCurrency(window.lboResults.inputs.transactionFees)], ['Debt 1 Interest Rate', `${window.lboResults.inputs.debt1InterestRate * 100}%`], ['Debt 1 Term', `${window.lboResults.inputs.debt1Term} Years`], ['Debt 1 Annual Amortization', `${window.lboResults.inputs.debt1Amortization * 100}%`], ['Projection Years', `${window.lboResults.inputs.projectionYears} Years`], ['Annual Revenue Growth', `${window.lboResults.inputs.revenueGrowth * 100}%`], ['EBITDA Margin', `${window.lboResults.inputs.ebitdaMargin * 100}%`], ['Exit EBITDA Multiple', `${window.lboResults.inputs.exitMultiple}x`] ]; pdf.autoTable({ startY: y, head: [['Parameter', 'Value']], body: inputData, theme: 'grid', styles: { fontSize: 9, cellPadding: 2, overflow: 'linebreak', lineColor: 200, lineWidth: 0.1 }, headStyles: { fillColor: BLUE_HEADER_COLOR, textColor: 255, fontStyle: 'bold' }, margin: { left: 15, right: 15 }, columnStyles: { 0: { cellWidth: 70 }, // Parameter column width 1: { cellWidth: 'auto' } // Value column width } }); y = pdf.autoTable.previous.finalY + 15; // --- Debt Schedule Section --- pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.text('2. Debt Schedule (Senior Debt)', 15, y); y += 8; const debtTableBody = window.lboResults.debtSchedule.map(row => [ row.year, formatCurrency(row.beginningBalance), formatCurrency(row.interestPayment), formatCurrency(row.principalPayment), formatCurrency(row.endingBalance) ]); pdf.autoTable({ startY: y, head: [['Year', 'Beginning Balance', 'Interest Payment', 'Principal Payment', 'Ending Balance']], body: debtTableBody, theme: 'grid', styles: { fontSize: 9, cellPadding: 2, overflow: 'linebreak', lineColor: 200, lineWidth: 0.1 }, headStyles: { fillColor: BLUE_HEADER_COLOR, textColor: 255, fontStyle: 'bold' }, margin: { left: 15, right: 15 }, didParseCell: function (data) { // Align currency columns right if (data.column.index >= 1) { // Apply to Beginning, Interest, Principal, Ending Balance data.cell.styles.halign = 'right'; } } }); y = pdf.autoTable.previous.finalY + 15; // --- Summary & Valuation Section --- pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.text('3. Summary & Valuation', 15, y); y += 8; // Check if content fits on one page, otherwise add a new page if (y + 100 > pdf.internal.pageSize.height - 15) { // Estimate space needed for summary pdf.addPage(); y = 15; // Reset y for new page } const summaryItems = [ { label: 'Total Sources:', value: formatCurrency(window.lboResults.financialSummary.totalSources), color: BLUE_TEXT_COLOR }, { label: 'Total Uses:', value: formatCurrency(window.lboResults.financialSummary.totalUses), color: RED_COLOR }, { label: 'Equity Contribution:', value: formatCurrency(window.lboResults.financialSummary.equityContribution), color: BLUE_TEXT_COLOR }, { label: 'Entry EBITDA:', value: formatCurrency(window.lboResults.financialSummary.entryEBITDA), color: GRAY_TEXT_COLOR }, { label: 'Exit EBITDA:', value: formatCurrency(window.lboResults.financialSummary.exitYearEBITDA), color: GRAY_TEXT_COLOR }, { label: 'Exit Enterprise Value:', value: formatCurrency(window.lboResults.financialSummary.exitEnterpriseValue), color: BLUE_TEXT_COLOR }, { label: 'Net Debt at Exit:', value: formatCurrency(window.lboResults.financialSummary.netDebtAtExit), color: RED_COLOR }, { label: 'Equity Value at Exit:', value: formatCurrency(window.lboResults.financialSummary.equityValueAtExit), color: BLUE_TEXT_COLOR }, { label: 'Multiple on Invested Capital (MOIC):', value: window.lboResults.financialSummary.moic.toFixed(2), color: GREEN_TEXT_COLOR }, { label: 'Internal Rate of Return (IRR):', value: formatPercentage(window.lboResults.financialSummary.irr), color: GREEN_TEXT_COLOR } ]; pdf.setFontSize(10); pdf.setFont('helvetica', 'normal'); // Reset font to normal for values summaryItems.forEach(item => { if (y + 7 > pdf.internal.pageSize.height - 15) { // Check space before adding line pdf.addPage(); y = 15; } pdf.setTextColor(BLACK_COLOR[0], BLACK_COLOR[1], BLACK_COLOR[2]); pdf.text(item.label, 15, y); pdf.setTextColor(item.color[0], item.color[1], item.color[2]); pdf.text(item.value, 150, y, { align: 'right' }); // Align value to the right y += 7; }); pdf.save('LBO_Model_Results.pdf'); } /** * Initializes DOM element references once the document is fully loaded. */ document.addEventListener('DOMContentLoaded', () => { // Input Elements purchasePriceInput = document.getElementById('purchasePrice'); debtPercentageInput = document.getElementById('debtPercentage'); transactionFeesInput = document.getElementById('transactionFees'); debt1InterestRateInput = document.getElementById('debt1InterestRate'); debt1TermInput = document.getElementById('debt1Term'); debt1AmortizationInput = document.getElementById('debt1Amortization'); projectionYearsInput = document.getElementById('projectionYears'); revenueGrowthInput = document.getElementById('revenueGrowth'); ebitdaMarginInput = document.getElementById('ebitdaMargin'); exitMultipleInput = document.getElementById('exitMultiple'); // Output Elements (Summary Tab) totalSourcesOutput = document.getElementById('totalSourcesOutput'); totalUsesOutput = document.getElementById('totalUsesOutput'); equityContributionOutput = document.getElementById('equityContributionOutput'); entryEBITDAOutput = document.getElementById('entryEBITDAOutput'); exitEBITDAOutput = document.getElementById('exitEBITDAOutput'); exitEVOutput = document.getElementById('exitEVOutput'); netDebtAtExitOutput = document.getElementById('netDebtAtExitOutput'); equityValueAtExitOutput = document.getElementById('equityValueAtExitOutput'); moicOutput = document.getElementById('moicOutput'); irrOutput = document.getElementById('irrOutput'); // Other Elements debtScheduleOutputDiv = document.getElementById('debtScheduleOutput'); messageBox = document.getElementById('messageBox'); // Initialize navigation button states updateNavigationButtons(); });