Button in der Planansicht -> Dialog: Erklaerung, Eingaben, Lauf, Ergebnis + Faecher. Statt einer festen Rendite/Inflation werden tausende Zufallspfade gerechnet und die Erfolgs-/Ruinwahrscheinlichkeit des Plans ausgewiesen. Kern (computePlan-Nahtstelle): - computePlan(plan, sample?) nimmt optional pro Jahr Inflation und pro Element/Jahr eine Rendite. Ohne sample bitgenau wie bisher (durch Golden Tests abgesichert). - Dazu Inflation auf ein kumulatives Deflator-Array umgestellt (statt (1+i)^t), damit sie pro Jahr variieren kann. Deterministisch identisch. - Reine Funktion ohne Server-Deps -> Simulation laeuft komplett im Browser, null Serverlast. ~10'000 Laeufe in ~1 s, Fortschritt alle 500 Laeufe (kein Freeze). Statistik (montecarlo.ts): - Fettschwaenzig (standardisierte Student-t, nu=5): Extremcrashs realistisch haeufig, eine Normalverteilung wuerde sie stark unterschaetzen. - Gemeinsamer Marktschock (rho=0.7): riskante Anlagen fallen im Crash zusammen, nicht gegeneinander. - Boeden: 0 % fuer PK/3a, -100 % sonst. Seedbar (reproduzierbar). - Zwei Renditezahlen: geplante (Zielbalken) vs. historische (Streu-Mittelpunkt) -- sonst waere P(>= geplantes Endvermoegen) immer ~50 %. UI: Erklaerung, pro Element/Inflation historischer Oe (Pflicht, kein Default) + Streuungsstufe (recherchierte sigma-Werte) + Anzahl Laeufe. Ergebnis: Ruin-/ Erfolgswahrscheinlichkeit, Faecher (10/50/90) + deterministische Linie. 7 MC-Tests inkl. deterministischer Aequivalenz, Vol-Drag, Reproduzierbarkeit, Boden, Ruin (41 -> 48). Keine DB-Aenderung. Spezifikation auf v0.7 (Kap. 4.12, 9.15). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
CreditCard,
|
||||
Dices,
|
||||
Home,
|
||||
Landmark,
|
||||
PiggyBank,
|
||||
@@ -32,6 +33,7 @@ import {
|
||||
type CellContext,
|
||||
} from "@/components/ElementDetail";
|
||||
import { PhaseDetail } from "@/components/PhaseDetail";
|
||||
import { MonteCarloDialog } from "@/components/MonteCarloDialog";
|
||||
import { PlanProfileFields, type ProfileDraft } from "@/components/PlanProfileFields";
|
||||
import { MoneyField } from "@/components/FormField";
|
||||
import { api } from "@/lib/api-client";
|
||||
@@ -104,6 +106,7 @@ export function PlanView({
|
||||
const [editTransition, setEditTransition] = useState<{ elementId: string; fromPhaseId: string } | null>(null);
|
||||
const [editPhaseCell, setEditPhaseCell] = useState<{ elementId: string; phaseId: string } | null>(null);
|
||||
const [showCashInit, setShowCashInit] = useState(false);
|
||||
const [showMonteCarlo, setShowMonteCarlo] = useState(false);
|
||||
// fromPhaseId des Cash-Uebergangs, der gerade bearbeitet wird.
|
||||
const [editCashTransition, setEditCashTransition] = useState<string | null>(null);
|
||||
const [valueMode, setValueMode] = useState<ValueMode>("nominal");
|
||||
@@ -350,6 +353,13 @@ export function PlanView({
|
||||
>
|
||||
<Plus className="h-4 w-4" /> Lebensphase
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowMonteCarlo(true)}
|
||||
className="ml-auto flex items-center gap-1.5 rounded-lg border border-border px-3 py-1.5 text-sm font-medium text-muted hover:bg-surface-2"
|
||||
>
|
||||
<Dices className="h-4 w-4" /> Monte-Carlo-Simulation durchführen
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -570,6 +580,10 @@ export function PlanView({
|
||||
/>
|
||||
)}
|
||||
|
||||
{showMonteCarlo && (
|
||||
<MonteCarloDialog plan={plan} computed={computed} onClose={() => setShowMonteCarlo(false)} />
|
||||
)}
|
||||
|
||||
{editCashTransition && (() => {
|
||||
const fromPhase = computed.phases.find((p) => p.id === editCashTransition);
|
||||
if (!fromPhase) return null;
|
||||
|
||||
Reference in New Issue
Block a user