Leveraged Buyout (LBO) Model Generator

Leveraged Buyout (LBO) Model Generator

1. Assumptions

Acquisition Details

Debt Tranche 1 (Senior Debt)

Operating Projections

Exit Assumptions

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 = ``; debtSchedule.forEach(row => { tableHtml += ` `; }); tableHtml += `
Year Beginning Balance Interest Payment Principal Payment Ending Balance
${row.year} ${formatCurrency(row.beginningBalance)} ${formatCurrency(row.interestPayment)} ${formatCurrency(row.principalPayment)} ${formatCurrency(row.endingBalance)}
`; debtScheduleOutputDiv.innerHTML = tableHtml; } /** * Calculates IRR using the Newton-Raphson method. * Source: Simplified version based on common financial formulas. * This is an approximation for non-annual cash flows, especially for 2 cash flows. * @param {number[]} cashFlows An array of cash flows, where cashFlows[0] is initial investment (negative). * @returns {number} The IRR as a decimal, or 0 if calculation fails. */ function calculateIRR(cashFlows) { // Function to calculate NPV for a given rate const npv = (rate) => { let sum = 0; for (let i = 0; i < cashFlows.length; i++) { sum += cashFlows[i] / Math.pow(1 + rate, i); } return sum; }; // Derivative of NPV function const derivativeNpv = (rate) => { let sum = 0; for (let i = 0; i < cashFlows.length; i++) { sum += -i * cashFlows[i] / Math.pow(1 + rate, i + 1); } return sum; }; let irrGuess = 0.1; // Initial guess for IRR (10%) const maxIterations = 100; const tolerance = 0.0001; // 0.01% for (let i = 0; i < maxIterations; i++) { const npvValue = npv(irrGuess); const derivativeValue = derivativeNpv(irrGuess); if (Math.abs(npvValue) < tolerance) { return irrGuess; } if (derivativeValue === 0) { // Avoid division by zero break; } irrGuess = irrGuess - (npvValue / derivativeValue); } return 0; // Return 0 if IRR cannot be found within iterations/tolerance } /** * Resets all input fields to their default values and hides output sections. */ function resetForm() { // Reset input values to defaults purchasePriceInput.value = "50000000"; debtPercentageInput.value = "60"; transactionFeesInput.value = "1000000"; debt1InterestRateInput.value = "5"; debt1TermInput.value = "5"; debt1AmortizationInput.value = "10"; projectionYearsInput.value = "5"; revenueGrowthInput.value = "5"; ebitdaMarginInput.value = "20"; exitMultipleInput.value = "8"; // Clear stored results window.lboResults = null; // Clear output divs debtScheduleOutputDiv.innerHTML = '

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(); });
Scroll to Top