Debt-to-Income (DTI) Ratio Analyzer

Step 1: Your Income & Monthly Housing Expenses

Income

Your total income before taxes and deductions.

Monthly Housing Expenses

If not included in P&I (escrowed).
If not included in P&I (escrowed).

Step 2: Your Other Monthly Debt Payments

List all other recurring monthly debt payments (e.g., minimum credit card payments, car loans, student loans, personal loans, alimony, child support).

Step 3: Debt-to-Income (DTI) Analysis

Step 4: Summary & Download Report

Complete the DTI calculation on Tab 3 to view the summary.

Understanding Your DTI:

Your Debt-to-Income (DTI) ratio is a key factor lenders use to assess your ability to manage monthly payments and repay debts. A lower DTI generally indicates a better balance between debt and income.

Front-End DTI specifically looks at your housing costs relative to your income. Back-End DTI includes all your monthly debt obligations.

Improving your DTI can involve increasing your income, reducing your debts, or both. This can positively impact your financial health and borrowing capacity.

Opportunity to Improve (44% - 49%): This DTI suggests a significant portion of your income goes to debt. While some loans might still be possible, lenders may have concerns or offer less favorable terms. Reducing debt or increasing income is advisable.

"; } else { // 50% or more interpretation += "

Action Recommended (50% or more): A DTI this high indicates a substantial debt burden. It may be difficult to qualify for new loans, and there might be little room for savings or unexpected costs. Consider strategies to significantly reduce debt or increase income.

"; } interpretation += "

Note: These are general guidelines. Lenders consider many factors, and specific requirements can vary. Maximum DTI limits can sometimes be higher for certain loan programs (e.g., up to 50% for some Qualified Mortgages), but a lower DTI is generally better.

"; return interpretation; } function displayDtiOverallSummary() { const container = document.getElementById('dtiOverallSummaryContainer'); if (!dtiReportData.dtiCalculations.hasOwnProperty('backEndDti')) { // Check if calculation has been run container.innerHTML = "

Please calculate your DTI on Tab 3 to view the summary.

"; document.getElementById('downloadDtiPdfButton').disabled = true; return; } const gmi = dtiReportData.income; const housingTotal = dtiReportData.housingExpenses.total || 0; const otherDebtsTotal = dtiReportData.dtiCalculations.totalOtherMonthlyDebts || 0; const frontEndDti = dtiReportData.dtiCalculations.frontEndDti || 0; const backEndDti = dtiReportData.dtiCalculations.backEndDti || 0; let summaryHTML = `

Your DTI Ratio Summary:

Gross Monthly Income: $${gmi.toFixed(2)}

Total Monthly Housing Expenses: $${housingTotal.toFixed(2)}

Total Other Monthly Debt Payments: $${otherDebtsTotal.toFixed(2)}


Calculated Front-End DTI: ${frontEndDti.toFixed(1)}%

Calculated Back-End DTI: ${backEndDti.toFixed(1)}%

${getDtiInterpretation(backEndDti)}
`; container.innerHTML = summaryHTML; document.getElementById('downloadDtiPdfButton').disabled = false; } function downloadDtiPdf() { if (!dtiReportData.dtiCalculations.hasOwnProperty('backEndDti')) { alert("Please calculate your DTI ratios first (Tab 3)."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF generation library (jsPDF) is not loaded.'); return; } const jsPDFConstructor = window.jspdf.jsPDF; const doc = new jsPDFConstructor(); if (typeof doc.autoTable !== 'function') { alert('jsPDF AutoTable plugin not loaded.'); return; } const data = dtiReportData; const primaryColor = '#007bff', textColor = '#212529', tableHeaderColor = '#e9ecef'; let yPos = 22; const pageHeight = doc.internal.pageSize.height; const margin = 20; function checkYPdf(increment = 10) { if (yPos + increment > pageHeight - margin) { doc.addPage(); yPos = margin; } } doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Debt-to-Income (DTI) Analysis Report", 14, yPos); yPos += 8; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Report Date: ${new Date().toLocaleDateString()}`, 14, yPos); yPos += 10; // Income checkYPdf(15); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Income", 14, yPos); yPos += 6; doc.autoTable({startY: yPos, body: [['Gross Monthly Income:', `$${data.income.toFixed(2)}`]], theme:'plain', styles:{fontSize:9, cellPadding:1.5}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 7; // Housing Expenses checkYPdf(20 + (data.housingExpenses.status === 'homeowner' ? 4*6 : 1*6)); // Estimate height doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Monthly Housing Expenses", 14, yPos); yPos += 6; let housingBody = [['Housing Status:', data.housingExpenses.status === 'homeowner' ? 'Homeowner' : 'Renter']]; if (data.housingExpenses.status === 'homeowner' && data.housingExpenses.details) { housingBody.push(['Mortgage P&I:', `$${(data.housingExpenses.details.p_i || 0).toFixed(2)}`]); housingBody.push(['Property Taxes:', `$${(data.housingExpenses.details.taxes || 0).toFixed(2)}`]); housingBody.push(['Homeowner\'s Insurance:', `$${(data.housingExpenses.details.insurance || 0).toFixed(2)}`]); housingBody.push(['HOA Dues:', `$${(data.housingExpenses.details.hoa || 0).toFixed(2)}`]); } else if (data.housingExpenses.status === 'renter' && data.housingExpenses.details) { housingBody.push(['Monthly Rent:', `$${(data.housingExpenses.details.rent || 0).toFixed(2)}`]); } housingBody.push([{content:'Total Housing Expenses:', styles:{fontStyle:'bold'}}, {content:`$${(data.housingExpenses.total || 0).toFixed(2)}`, styles:{fontStyle:'bold'}}]); doc.autoTable({startY: yPos, body: housingBody, theme:'plain', styles:{fontSize:9, cellPadding:1.5}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 7; if (data.otherDebts && data.otherDebts.length > 0) { checkYPdf(20 + data.otherDebts.length * 6); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Other Monthly Debts", 14, yPos); yPos += 6; const otherDebtsTableBody = data.otherDebts.map(d => [d.name, `$${d.amount.toFixed(2)}`]); doc.autoTable({ startY: yPos, head: [['Debt Name/Type', 'Monthly Payment ($)']], body: otherDebtsTableBody, theme: 'grid', headStyles: {fillColor: tableHeaderColor, textColor: textColor, fontStyle:'bold', fontSize:9}, styles: {fontSize:9, cellPadding:1.5}, columnStyles: {1:{halign:'right'}} }); yPos = doc.lastAutoTable.finalY; } checkYPdf(10); doc.setFontSize(10); doc.setFont(undefined, 'bold'); doc.text(`Total Other Monthly Debt Payments: $${(data.dtiCalculations.totalOtherMonthlyDebts || 0).toFixed(2)}`, 14, yPos); yPos += 10; doc.setFont(undefined, 'normal'); checkYPdf(30); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("DTI Ratio Analysis", 14, yPos); yPos += 6; let dtiResultsBody = [ [{content: 'Front-End DTI (Housing Ratio):', styles:{fontStyle:'bold'}}, {content: `${(data.dtiCalculations.frontEndDti || 0).toFixed(1)}%`}], [{content: 'Back-End DTI (Total Debt Ratio):', styles:{fontStyle:'bold'}}, {content: `${(data.dtiCalculations.backEndDti || 0).toFixed(1)}%`}] ]; doc.autoTable({ startY: yPos, body: dtiResultsBody, theme:'plain', styles:{fontSize:10, cellPadding:1.5}, columnStyles:{0:{fontStyle:'bold'}}, didDrawCell: function (hookData) { if (hookData.column.index === 1) { // Styling for the DTI percentage values let dtiVal = parseFloat(hookData.cell.text[0].replace('%','')); let isFront = hookData.row.index === 0; const dtiColor = getDtiPdfColor(dtiVal, isFront); doc.setTextColor(dtiColor[0], dtiColor[1], dtiColor[2]); doc.setFont(undefined, 'bold'); } }, willDrawCell: function(hookData){ // Reset for next cells doc.setTextColor(textColor); doc.setFont(undefined, 'normal'); } }); yPos = doc.lastAutoTable.finalY + 7; checkYPdf(60); doc.setFontSize(10); doc.setTextColor(textColor); const interpretationText = getDtiInterpretation(data.dtiCalculations.backEndDti || 0) .replace(/

.*?<\/h4>/gi, '') // Remove h4 tag .replace(/

(.*?)<\/strong>(.*?)<\/p>/gi, '$1$2\n') // Strong tags with class .replace(/

.*?(.*?)<\/strong>.*?<\/p>/gi, '$1\n') // For other strong tags .replace(/(.*?)<\/strong>/gi, '$1') // Remaining strong tags .replace(/(.*?)<\/small>/gi, '\n($1)') .replace(/

(.*?)<\/p>/gi, '$1\n') .replace(/\n\s*\n/g, '\n') // Remove multiple blank lines .trim(); const splitText = doc.splitTextToSize(interpretationText, 180); doc.setFontSize(9.5); doc.text("Understanding Your Back-End DTI:", 14, yPos); yPos +=5; splitText.forEach(line => { checkYPdf(5); doc.text(line, 14, yPos); yPos += 5; }); doc.save("DTI_Analysis_Report.pdf"); } function getDtiPdfColor(dti, isFrontEnd) { const classColor = getDtiClass(dti, isFrontEnd); if (classColor === 'dti-good') return [40, 167, 69]; // Green if (classColor === 'dti-fair') return [253, 126, 20]; // Orange return [220, 53, 69]; // Red for high } // Initial calls updateDtiNavButtons(); toggleHousingFields(); calculateFrontEndDti(false); // Calculate on load but don't force display update in the div until income is entered

Scroll to Top