Scan to open on your phone
Point a camera at the QR code - it opens this exact paste, no app needed.
https://codepastes.com/zzgsv247jbtj6azcunbenanntPlain Text
<!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