MHK - meinhauskapital

In 24 Monaten finanzierungsbereit: fokussiert sparen, Bausparvertrag nutzen und in Cash, Gold, Bitcoin strukturiert Eigenkapital aufbauen.

Modus

Was ist finanzierbar?

Formel fix: finanzierbarer Kaufpreis = Nettoeinkommen x 95

Dein EK-Plan

Monatliche Strategie

(function () { const STORAGE_KEY = "mhk_rechner_v1"; const DEFAULTS = { mode: "projection", netIncome: 3000, liabilities: 0, currentEquity: 0, externalEquity: 10000, monthlyBudget: 1000, durationMonths: 24, ekQuotePct: 20, bausparSplitPct: 40, cashSplitPct: 50, goldSplitPct: 30, btcSplitPct: 20, bausparReturnPct: 2, cashReturnPct: 2, goldReturnPct: 4, btcReturnPct: 12 }; const CalculatorEngine = { computeFinanzierbar(netto) { return netto * 95; }, computeEkTarget(finanzierbar, ekQuotePct) { return finanzierbar * (ekQuotePct / 100); }, monthlyRate(annualPct) { const annual = annualPct / 100; return Math.pow(1 + annual, 1 / 12) - 1; }, futureValueLumpSum(pv, annualRatePct, months) { const r = this.monthlyRate(annualRatePct); return pv * Math.pow(1 + r, months); }, futureValueMonthly(contrib, annualRatePct, months, endOfMonth) { const r = this.monthlyRate(annualRatePct); if (months <= 0) return 0; if (Math.abs(r) < 1e-12) return contrib * months; const growthSeries = (Math.pow(1 + r, months) - 1) / r; return endOfMonth ? contrib * growthSeries : contrib * growthSeries * (1 + r); }, annuityFactor(annualRatePct, months, endOfMonth) { if (months <= 0) return 0; const r = this.monthlyRate(annualRatePct); if (Math.abs(r) < 1e-12) return months; const base = (Math.pow(1 + r, months) - 1) / r; return endOfMonth ? base : base * (1 + r); }, projectBuckets(input, monthlyContribution) { const months = input.durationMonths; const startTotal = input.currentEquity + input.externalEquity; const bausparSplit = input.bausparSplitPct / 100; const portfolioSplit = 1 - bausparSplit; const cashSplit = input.cashSplitPct / 100; const goldSplit = input.goldSplitPct / 100; const btcSplit = input.btcSplitPct / 100; const startBauspar = startTotal * bausparSplit; const startPortfolio = startTotal * portfolioSplit; const startCash = startPortfolio * cashSplit; const startGold = startPortfolio * goldSplit; const startBtc = startPortfolio * btcSplit; const monthlyBauspar = monthlyContribution * bausparSplit; const monthlyPortfolio = monthlyContribution * portfolioSplit; const monthlyCash = monthlyPortfolio * cashSplit; const monthlyGold = monthlyPortfolio * goldSplit; const monthlyBtc = monthlyPortfolio * btcSplit; const bauspar = this.futureValueLumpSum(startBauspar, input.bausparReturnPct, months) + this.futureValueMonthly(monthlyBauspar, input.bausparReturnPct, months, true); const cash = this.futureValueLumpSum(startCash, input.cashReturnPct, months) + this.futureValueMonthly(monthlyCash, input.cashReturnPct, months, true); const gold = this.futureValueLumpSum(startGold, input.goldReturnPct, months) + this.futureValueMonthly(monthlyGold, input.goldReturnPct, months, true); const btc = this.futureValueLumpSum(startBtc, input.btcReturnPct, months) + this.futureValueMonthly(monthlyBtc, input.btcReturnPct, months, true); return { bauspar: bauspar, cash: cash, gold: gold, btc: btc }; }, requiredMonthlyForTarget(input) { const months = input.durationMonths; const startTotal = input.currentEquity + input.externalEquity; const bausparSplit = input.bausparSplitPct / 100; const portfolioSplit = 1 - bausparSplit; const cashSplit = input.cashSplitPct / 100; const goldSplit = input.goldSplitPct / 100; const btcSplit = input.btcSplitPct / 100; const finanzierbar = this.computeFinanzierbar(input.netIncome); const target = this.computeEkTarget(finanzierbar, input.ekQuotePct); const fvStartBauspar = startTotal * bausparSplit * Math.pow(1 + this.monthlyRate(input.bausparReturnPct), months); const fvStartCash = startTotal * portfolioSplit * cashSplit * Math.pow(1 + this.monthlyRate(input.cashReturnPct), months); const fvStartGold = startTotal * portfolioSplit * goldSplit * Math.pow(1 + this.monthlyRate(input.goldReturnPct), months); const fvStartBtc = startTotal * portfolioSplit * btcSplit * Math.pow(1 + this.monthlyRate(input.btcReturnPct), months); const fvStart = fvStartBauspar + fvStartCash + fvStartGold + fvStartBtc; const monthlyFactor = bausparSplit * this.annuityFactor(input.bausparReturnPct, months, true) + portfolioSplit * ( cashSplit * this.annuityFactor(input.cashReturnPct, months, true) + goldSplit * this.annuityFactor(input.goldReturnPct, months, true) + btcSplit * this.annuityFactor(input.btcReturnPct, months, true) ); if (monthlyFactor <= 0) return 0; return Math.max(0, (target - fvStart) / monthlyFactor); }, run(input) { const finanzierbar = this.computeFinanzierbar(input.netIncome); const ekTarget = this.computeEkTarget(finanzierbar, input.ekQuotePct); const requiredMonthly = this.requiredMonthlyForTarget(input); const monthlyContribution = input.mode === "projection" ? input.monthlyBudget : requiredMonthly; const buckets = this.projectBuckets(input, monthlyContribution); const projectedTotal = buckets.bauspar + buckets.cash + buckets.gold + buckets.btc; const gap = ekTarget - projectedTotal; const progressRatio = ekTarget > 0 ? projectedTotal / ekTarget : 0; return { finanzierbar: finanzierbar, ekTarget: ekTarget, projectedTotal: projectedTotal, requiredMonthly: requiredMonthly, buckets: buckets, gap: gap, progressRatio: progressRatio, onTrack: projectedTotal >= ekTarget }; } }; const currency = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }); const percent = new Intl.NumberFormat("de-DE", { style: "percent", maximumFractionDigits: 1 }); const ids = [ "netIncome","liabilities","currentEquity","externalEquity","monthlyBudget","durationMonths", "ekQuotePct","bausparSplitPct","cashSplitPct","goldSplitPct","btcSplitPct", "bausparReturnPct","cashReturnPct","goldReturnPct","btcReturnPct" ]; function getMode() { const selected = document.querySelector('input[name="mode"]:checked'); return selected ? selected.value : "projection"; } function setMode(mode) { const radio = document.querySelector('input[name="mode"][value="' + mode + '"]'); if (radio) radio.checked = true; } function num(v) { const parsed = Number(v); return Number.isFinite(parsed) ? parsed : NaN; } function readInput() { return { mode: getMode(), netIncome: num(document.getElementById("netIncome").value), liabilities: num(document.getElementById("liabilities").value), currentEquity: num(document.getElementById("currentEquity").value), externalEquity: num(document.getElementById("externalEquity").value), monthlyBudget: num(document.getElementById("monthlyBudget").value), durationMonths: num(document.getElementById("durationMonths").value), ekQuotePct: num(document.getElementById("ekQuotePct").value), bausparSplitPct: num(document.getElementById("bausparSplitPct").value), cashSplitPct: num(document.getElementById("cashSplitPct").value), goldSplitPct: num(document.getElementById("goldSplitPct").value), btcSplitPct: num(document.getElementById("btcSplitPct").value), bausparReturnPct: num(document.getElementById("bausparReturnPct").value), cashReturnPct: num(document.getElementById("cashReturnPct").value), goldReturnPct: num(document.getElementById("goldReturnPct").value), btcReturnPct: num(document.getElementById("btcReturnPct").value) }; } function validate(input) { const errors = []; const nonNegativeFields = [ ["netIncome","Nettoeinkommen"],["liabilities","Verbindlichkeiten"],["currentEquity","Aktuelles Eigenkapital"], ["externalEquity","Eigenkapital aus anderen Quellen"],["monthlyBudget","Monatlich verfügbar"],["ekQuotePct","EK-Quote"], ["bausparSplitPct","Bauspar-Split"],["cashSplitPct","Cash-Split"],["goldSplitPct","Gold-Split"],["btcSplitPct","Bitcoin-Split"], ["bausparReturnPct","Bauspar-Rendite"],["cashReturnPct","Cash-Rendite"],["goldReturnPct","Gold-Rendite"],["btcReturnPct","Bitcoin-Rendite"] ]; for (let i = 0; i < nonNegativeFields.length; i++) { const field = nonNegativeFields[i][0]; const label = nonNegativeFields[i][1]; if (!Number.isFinite(input[field])) errors.push(label + ": bitte einen gültigen Zahlenwert eingeben."); else if (input[field] < 0) errors.push(label + ": darf nicht negativ sein."); } if (!Number.isFinite(input.durationMonths) || input.durationMonths <= 0 || !Number.isInteger(input.durationMonths)) { errors.push("Laufzeit: bitte eine ganze Zahl größer 0 eingeben."); } if (input.bausparSplitPct > 100) errors.push("Bauspar-Split darf maximal 100% sein."); const portfolioSum = input.cashSplitPct + input.goldSplitPct + input.btcSplitPct; if (Math.abs(portfolioSum - 100) > 0.01) errors.push("Portfolio-Split (Cash/Gold/Bitcoin) muss 100% ergeben."); return errors; } function renderErrors(errors) { const box = document.getElementById("errors"); if (!box) return; if (!errors.length) { box.style.display = "none"; box.innerHTML = ""; return; } box.style.display = "block"; box.innerHTML = ""; } function formatEur(value) { return currency.format(Number.isFinite(value) ? value : 0); } function render(result) { document.getElementById("kpiProjected").textContent = formatEur(result.projectedTotal); document.getElementById("kpiAffordable").textContent = formatEur(result.finanzierbar); document.getElementById("kpiTarget").textContent = formatEur(result.ekTarget); document.getElementById("kpiRequiredMonthly").textContent = formatEur(result.requiredMonthly); const gapLabel = result.gap > 0 ? "Lücke: " + formatEur(result.gap) : "Überschuss: " + formatEur(Math.abs(result.gap)); document.getElementById("gapText").textContent = gapLabel; const capped = Math.max(0, Math.min(1.5, result.progressRatio)); document.getElementById("progressBar").style.width = Math.min(100, capped * 100) + "%"; document.getElementById("progressText").textContent = "Zielerreichung: " + percent.format(Math.max(0, result.progressRatio)); const statusEl = document.getElementById("statusText"); statusEl.textContent = result.onTrack ? "im Plan" : "unter Plan"; statusEl.className = "status " + (result.onTrack ? "ok" : "bad"); document.getElementById("bucketBauspar").textContent = formatEur(result.buckets.bauspar); document.getElementById("bucketCash").textContent = formatEur(result.buckets.cash); document.getElementById("bucketGold").textContent = formatEur(result.buckets.gold); document.getElementById("bucketBtc").textContent = formatEur(result.buckets.btc); } function updateModeUi(mode) { const monthlyField = document.getElementById("monthlyBudget"); if (monthlyField) monthlyField.disabled = mode === "required_monthly"; } function setValues(values) { setMode(values.mode || DEFAULTS.mode); for (let i = 0; i < ids.length; i++) { const id = ids[i]; const el = document.getElementById(id); if (el) el.value = values[id]; } updateModeUi(getMode()); } function save(values) { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(values)); } catch (e) {} } function load() { try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return null; const parsed = JSON.parse(raw); return Object.assign({}, DEFAULTS, parsed); } catch (e) { return null; } } function recalc() { const input = readInput(); const errors = validate(input); renderErrors(errors); updateModeUi(input.mode); save(input); if (errors.length) return; const result = CalculatorEngine.run(input); render(result); } function resetDefaults() { setValues(DEFAULTS); save(DEFAULTS); recalc(); } function init() { if (!document.getElementById("netIncome")) return; const saved = load(); setValues(saved || DEFAULTS); for (let i = 0; i < ids.length; i++) { const el = document.getElementById(ids[i]); if (el) el.addEventListener("input", recalc); } const modeInputs = document.querySelectorAll('input[name="mode"]'); for (let i = 0; i < modeInputs.length; i++) { modeInputs[i].addEventListener("change", recalc); } const resetBtn = document.getElementById("resetBtn"); if (resetBtn) resetBtn.addEventListener("click", resetDefaults); recalc(); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init); } else { init(); } })();