Property Market Crash Risk Analyzer

Property Market Crash Risk Analyzer

Analyze key indicators to assess the risk of a housing market downturn.

Key Risk Factors

    `; } else { let formHtml = `

    ${category}

    `; for (const key in appData[category]) { formHtml += createFormGroup(key, appData[category][key], category); } formHtml += '
    '; content.innerHTML = formHtml; } tabContentsContainer.appendChild(content); tabContents.push(content); }); updateTabs(); calculateAll(); setupEventListeners(); } function calculateAll() { const econ = appData['Economic Indicators']; const market = appData['Real Estate Market Health']; const afford = appData['Affordability Metrics']; let riskScore = 0; const riskFactors = []; // Interest Rate Risk const interestRate = parseFloat(econ.interest_rate.value) || 0; if (interestRate > 7) { riskScore += 25; riskFactors.push('High mortgage rates straining affordability.'); } else if (interestRate > 5.5) { riskScore += 10; } // Unemployment Risk const unemployment = parseFloat(econ.unemployment_rate.value) || 0; if (unemployment > 5) { riskScore += 25; riskFactors.push('Elevated unemployment could lead to defaults.'); } else if (unemployment > 4) { riskScore += 10; } // Inventory Risk const inventory = parseFloat(market.inventory_months.value) || 0; if (inventory < 3) { riskScore += 15; riskFactors.push('Low inventory is driving prices up unsustainably.'); } else if (inventory > 6) { riskScore += 15; riskFactors.push('High inventory suggests weakening demand.'); } // Bidding War Risk const aboveAsking = parseFloat(market.sales_above_asking.value) || 0; if (aboveAsking > 50) { riskScore += 15; riskFactors.push('High percentage of homes selling above ask indicates market froth.'); } // Affordability Risk const homePrice = parseFloat(afford.median_home_price.value) || 0; const income = parseFloat(afford.median_income.value) || 0; const priceToIncome = income > 0 ? homePrice / income : 100; if (priceToIncome > 5) { riskScore += 20; riskFactors.push('Price-to-income ratio is historically high.'); } else if (priceToIncome > 4) { riskScore += 10; } riskScore = Math.min(100, riskScore); updateDashboard(riskScore, riskFactors); } function updateDashboard(score, factors) { const riskTextEl = document.getElementById('risk-level-text'); const riskFactorsList = document.getElementById('risk-factors-list'); let level = ''; let color = ''; if (score < 30) { level = 'Low'; color = '#22c55e'; } else if (score < 50) { level = 'Moderate'; color = '#facc15'; } else if (score < 75) { level = 'Elevated'; color = '#f97316'; } else { level = 'High'; color = '#ef4444'; } riskTextEl.textContent = level; riskTextEl.style.color = color; riskFactorsList.innerHTML = ''; if (factors.length > 0) { factors.forEach(f => { const li = document.createElement('li'); li.textContent = f; riskFactorsList.appendChild(li); }); } else { riskFactorsList.innerHTML = '
  • No significant risk factors identified.
  • '; } createRiskGauge(score, color); } function createRiskGauge(score, color) { const container = document.getElementById('risk-o-meter'); container.innerHTML = ''; const ctx = document.getElementById('risk-chart').getContext('2d'); if (riskChart) riskChart.destroy(); riskChart = new Chart(ctx, { type: 'doughnut', data: { datasets: [{ data: [score, 100 - score], backgroundColor: [color, '#e5e7eb'], borderWidth: 0, circumference: 180, rotation: 270, }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '70%', plugins: { tooltip: { enabled: false } } } }); } function updateTabs() { tabs.forEach((tab, i) => tab.classList.toggle('active', i === currentTabIndex)); tabContents.forEach((c, i) => c.classList.toggle('active', i === currentTabIndex)); prevBtn.disabled = currentTabIndex === 0; nextBtn.disabled = currentTabIndex === tabs.length - 1; prevBtn.classList.toggle('opacity-50', currentTabIndex === 0); nextBtn.classList.toggle('opacity-50', currentTabIndex === tabs.length - 1); } function setupEventListeners() { tabsContainer.addEventListener('click', (e) => { if (e.target.classList.contains('tab')) { currentTabIndex = parseInt(e.target.dataset.index); updateTabs(); } }); prevBtn.addEventListener('click', () => { if (currentTabIndex > 0) { currentTabIndex--; updateTabs(); } }); nextBtn.addEventListener('click', () => { if (currentTabIndex < tabs.length - 1) { currentTabIndex++; updateTabs(); } }); tabContentsContainer.addEventListener('input', (e) => { if (e.target.tagName === 'INPUT') { const category = e.target.dataset.category; const key = e.target.dataset.key; if (appData[category] && appData[category][key]) { appData[category][key].value = e.target.value; calculateAll(); } } }); document.getElementById('pdf-download-btn').addEventListener('click', generatePdf); } function generatePdf() { const { jsPDF } = jspdf; const pdf = new jsPDF(); const pdfContainer = document.createElement('div'); pdfContainer.style.cssText = 'position:absolute; left:-9999px; width:800px; padding:20px; font-family:Inter,sans-serif; color:#1f2937; background:white;'; const chartCanvas = document.getElementById('risk-chart'); const chartImgData = chartCanvas.toDataURL('image/png', 1.0); let html = `

    Market Crash Risk Analysis

    ${document.getElementById('risk-level-text').textContent} Risk

    Key Risk Factors

    ${document.getElementById('risk-factors-list').outerHTML}`; for (const category in appData) { if (category === 'Dashboard') continue; html += `

    ${category}

    `; for (const key in appData[category]) { const item = appData[category][key]; html += ``; } html += '
    ${item.label}:${item.value}${item.suffix || ''}
    '; } pdfContainer.innerHTML = html; document.body.appendChild(pdfContainer); html2canvas(pdfContainer, { scale: 2 }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const { width, height } = pdf.internal.pageSize; const imgHeight = canvas.height * width / canvas.width; pdf.addImage(imgData, 'PNG', 0, 0, width, imgHeight); pdf.save('market-risk-analysis.pdf'); document.body.removeChild(pdfContainer); }); } initialize(); });
    Scroll to Top