unbenannt

Pasted Oct 16, 2026, 1:58 PM1 file400 lines

Scan to open on your phone

Point a camera at the QR code - it opens this exact paste, no app needed.

https://codepastes.com/zzgsv247jbtj6azc
unbenannt
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Immobilien-Simulator: Mieten vs. Kaufen</title>
    <style>
        :root {
            --primary: #2563eb;
            --primary-dark: #1d4ed8;
            --background: #f8fafc;
            --card-bg: #ffffff;
            --text: #1e293b;
            --text-light: #64748b;
            --border: #e2e8f0;
            --success: #16a34a;
            --accent: #9333ea;
        }

        body {
            font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            background-color: var(--background);
            color: var(--text);
            margin: 0;
            padding: 20px;
            line-height: 1.5;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
        }

        h1 {
            text-align: center;
            color: var(--text);
            margin-bottom: 5px;
        }

        p.subtitle {
            text-align: center;
            color: var(--text-light);
            margin-top: 0;
            margin-bottom: 30px;
        }

        .grid {
            display: grid;
            grid-template-columns: 1fr 1.5fr;
            gap: 24px;
        }

        @media (max-width: 900px) {
            .grid {
                grid-template-columns: 1fr;
            }
        }

        .card {
            background: var(--card-bg);
            border: 1px solid var(--border);
            border-radius: 12px;
            padding: 24px;
            box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
        }

        h2 {
            font-size: 1.25rem;
            margin-top: 0;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 2px solid var(--border);
        }

        .input-group {
            margin-bottom: 16px;
        }

        label {
            display: block;
            font-size: 0.875rem;
            font-weight: 600;
            margin-bottom: 6px;
        }

        .hint {
            font-size: 0.75rem;
            color: var(--text-light);
            margin-top: 2px;
        }

        input[type="number"], select {
            width: 100%;
            padding: 8px 12px;
            border: 1px solid var(--border);
            border-radius: 6px;
            font-size: 1rem;
            box-sizing: border-box;
        }

        input[type="number"]:focus, select:focus {
            outline: none;
            border-color: var(--primary);
            box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
        }

        .results-summary {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 16px;
            margin-bottom: 24px;
        }

        .metric-card {
            background: var(--background);
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 16px;
            text-align: center;
        }

        .metric-card.winner {
            border-color: var(--success);
            background: #f0fdf4;
        }

        .metric-title {
            font-size: 0.875rem;
            color: var(--text-light);
            margin-bottom: 4px;
        }

        .metric-value {
            font-size: 1.5rem;
            font-weight: 700;
        }

        .table-container {
            overflow-x: auto;
            max-height: 400px;
            overflow-y: auto;
            border: 1px solid var(--border);
            border-radius: 8px;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            text-align: right;
            font-size: 0.875rem;
        }

        th, td {
            padding: 10px 12px;
            border-bottom: 1px solid var(--border);
        }

        th {
            background: var(--background);
            position: sticky;
            top: 0;
            z-index: 1;
            font-weight: 600;
        }

        th:first-child, td:first-child {
            text-align: left;
        }

        .highlight-buy {
            color: var(--primary);
            font-weight: 600;
        }

        .highlight-rent {
            color: var(--accent);
            font-weight: 600;
        }
    </style>
</head>
<body>

<div class="container">
    <h1>Mieten vs. Kaufen Simulator</h1>
    <p class="subtitle">Vergleiche langfristig die finanzielle Entwicklung von Immobilieneigentum gegenüber Mieten und paralleler Kapitalanlage.</p>

    <div class="grid">
        <!-- Eingabebereich -->
        <div class="card">
            <h2>Parameter</h2>
            
            <div class="input-group">
                <label for="propertyPrice">Kaufpreis Immobilie (€)</label>
                <input type="number" id="propertyPrice" value="400000" step="10000" oninput="calculate()">
            </div>

            <div class="input-group">
                <label for="equity">Eigenkapital (€)</label>
                <input type="number" id="equity" value="100000" step="5000" oninput="calculate()">
                <div class="hint">Inklusive Kaufnebenkosten</div>
            </div>

            <div class="input-group">
                <label for="interestRate">Sollzins p.a. (%)</label>
                <input type="number" id="interestRate" value="3.8" step="0.1" oninput="calculate()">
            </div>

            <div class="input-group">
                <label for="repaymentRate">Anfängliche Tilgung p.a. (%)</label>
                <input type="number" id="repaymentRate" value="2.0" step="0.1" oninput="calculate()">
            </div>

            <div class="input-group">
                <label for="purchaseCostsPct">Kaufnebenkosten (%)</label>
                <input type="number" id="purchaseCostsPct" value="10.5" step="0.5" oninput="calculate()">
                <div class="hint">Grunderwerbsteuer, Notar, Grundbuch, Makler</div>
            </div>

            <div class="input-group">
                <label for="initialRent">Kaltmiete Monat (€)</label>
                <input type="number" id="initialRent" value="1200" step="50" oninput="calculate()">
            </div>

            <div class="input-group">
                <label for="maintenanceRate">Instandhaltung /qm bzw. % p.a.</label>
                <input type="number" id="maintenanceRate" value="1.0" step="0.1" oninput="calculate()">
                <div class="hint">% vom Immobilienwert pro Jahr</div>
            </div>

            <div class="input-group">
                <label for="propertyAppreciation">Immobilien-Wertsteigerung p.a. (%)</label>
                <input type="number" id="propertyAppreciation" value="1.5" step="0.1" oninput="calculate()">
            </div>

            <div class="input-group">
                <label for="investmentReturn">Rendite Alternativ-Anlage (ETF) p.a. (%)</label>
                <input type="number" id="investmentReturn" value="6.0" step="0.5" oninput="calculate()">
                <div class="hint">Rendite für nicht ausgegebenes Kapital / Eigenkapital</div>
            </div>

            <div class="input-group">
                <label for="timeHorizon">Betrachtungszeitraum (Jahre)</label>
                <input type="number" id="timeHorizon" value="20" step="1" min="1" max="50" oninput="calculate()">
            </div>
        </div>

        <!-- Ausgabebereich -->
        <div class="card">
            <h2>Ergebnisübersicht</h2>
            
            <div class="results-summary">
                <div class="metric-card" id="cardBuy">
                    <div class="metric-title">Netto-Vermögen Kaufen</div>
                    <div class="metric-value" id="resBuyWealth">0 €</div>
                    <div class="hint" id="resBuyDetail">Immobilienwert minus Restschuld</div>
                </div>
                <div class="metric-card" id="cardRent">
                    <div class="metric-title">Netto-Vermögen Mieten + ETF</div>
                    <div class="metric-value" id="resRentWealth">0 €</div>
                    <div class="hint" id="resRentDetail">Kapitalanlage-Depot</div>
                </div>
            </div>

            <h3 style="font-size: 1rem; margin-bottom: 10px;">Verlauf über die Jahre</h3>
            <div class="table-container">
                <table id="resultTable">
                    <thead>
                        <tr>
                            <th>Jahr</th>
                            <th>Kauf: Immobilienwert</th>
                            <th>Kauf: Restschuld</th>
                            <th>Kauf: Netto</th>
                            <th>Miete: Depot</th>
                            <th>Sieger</th>
                        </tr>
                    </thead>
                    <tbody id="tableBody">
                        <!-- Wird per JS gefüllt -->
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

<script>
function calculate() {
    // Eingaben einlesen
    const price = parseFloat(document.getElementById('propertyPrice').value) || 0;
    const equity = parseFloat(document.getElementById('equity').value) || 0;
    const interestRate = (parseFloat(document.getElementById('interestRate').value) || 0) / 100;
    const initialRepayment = (parseFloat(document.getElementById('repaymentRate').value) || 0) / 100;
    const purchaseCostsPct = (parseFloat(document.getElementById('purchaseCostsPct').value) || 0) / 100;
    let monthlyRent = parseFloat(document.getElementById('initialRent').value) || 0;
    const maintenanceRate = (parseFloat(document.getElementById('maintenanceRate').value) || 0) / 100;
    const propertyAppreciation = (parseFloat(document.getElementById('propertyAppreciation').value) || 0) / 100;
    const investmentReturn = (parseFloat(document.getElementById('investmentReturn').value) || 0) / 100;
    const years = parseInt(document.getElementById('timeHorizon').value) || 20;

    // Finanzierungsberechnung
    const purchaseCosts = price * purchaseCostsPct;
    const loanAmount = Math.max(0, price + purchaseCosts - equity);
    
    // Annahme: Anfängliche Annuität = Darlehen * (Zins + anfängliche Tilgung)
    const initialAnnuaity = loanAmount * (interestRate + initialRepayment);
    const monthlyRateBuy = initialAnnuaity / 12;

    // Beim Mieten: Das überschüssige Eigenkapital (abzgl. Kaufnebenkosten, die "verloren" sind) wird angelegt.
    // Wenn Eigenkapital kleiner als Kaufnebenkosten ist, startet das Depot bei 0.
    let renterDepot = Math.max(0, equity - purchaseCosts);

    let propertyValue = price;
    let remainingLoan = loanAmount;

    let tableHTML = '';
    
    let finalBuyNet = 0;
    let finalRentNet = 0;

    for (let year = 1; year <= years; year++) {
        // 1. Jahr Immobilien & Kredit
        let yearlyInterest = 0;
        let yearlyPrincipal = 0;
        let currentLoan = remainingLoan;

        // Kreditberechnung Monat für Monat im Jahr genauer abbilden
        for (let m = 0; m < 12; m++) {
            if (currentLoan > 0) {
                let monthInterest = currentLoan * (interestRate / 12);
                let monthPrincipal = Math.min(currentLoan, (initialAnnuaity / 12) - monthInterest);
                yearlyInterest += monthInterest;
                yearlyPrincipal += monthPrincipal;
                currentLoan -= monthPrincipal;
            }
        }
        remainingLoan = currentLoan;

        // Instandhaltungskosten & Wertsteigerung
        let maintenanceCosts = propertyValue * maintenanceRate;
        propertyValue *= (1 + propertyAppreciation);

        // Gesamtkosten Käufer in diesem Jahr (Rate + Instandhaltung)
        let totalBuyCostYear = (monthlyRateBuy * 12) + maintenanceCosts;

        // 2. Jahr Miete & Depot
        let yearlyRentCost = monthlyRent * 12;
        monthlyRent *= 1.02; // Annahme: 2% Mietsteigerung p.a.

        // Differenz zwischen Kaufen-Kosten und Mieten-Kosten wandert ins Depot (oder wird abgezogen)
        let cashDifference = totalBuyCostYear - yearlyRentCost; 

        // Depot wächst durch Rendite + monatliche/jährliche Differenz
        renterDepot = (renterDepot + cashDifference) * (1 + investmentReturn);

        let buyNet = propertyValue - remainingLoan;
        let rentNet = renterDepot;

        if (year === years) {
            finalBuyNet = buyNet;
            finalRentNet = rentNet;
        }

        let winnerText = buyNet > rentNet ? '<span class="highlight-buy">Kaufen</span>' : '<span class="highlight-rent">Mieten</span>';

        tableHTML += `
            <tr>
                <td>Jahr ${year}</td>
                <td>${Math.round(propertyValue).toLocaleString('de-DE')} €</td>
                <td>${Math.round(remainingLoan).toLocaleString('de-DE')} €</td>
                <td><strong>${Math.round(buyNet).toLocaleString('de-DE')} €</strong></td>
                <td><strong>${Math.round(rentNet).toLocaleString('de-DE')} €</strong></td>
                <td>${winnerText}</td>
            </tr>
        `;
    }

    // UI aktualisieren
    document.getElementById('tableBody').innerHTML = tableHTML;
    document.getElementById('resBuyWealth').innerText = Math.round(finalBuyNet).toLocaleString('de-DE') + ' €';
    document.getElementById('resRentWealth').innerText = Math.round(finalRentNet).toLocaleString('de-DE') + ' €';

    const cardBuy = document.getElementById('cardBuy');
    const cardRent = document.getElementById('cardRent');

    if (finalBuyNet >= finalRentNet) {
        cardBuy.classList.add('winner');
        cardRent.classList.remove('winner');
    } else {
        cardRent.classList.add('winner');
        cardBuy.classList.remove('winner');
    }
}

// Initialer Aufruf beim Laden
window.onload = calculate;
</script>

</body>
</html>

13,857 chars · codepastes.com