Damit ist der geplante Funktionsumfang beisammen. Phase 4 abgeschlossen - Konfigurierbare Cockpit-Kacheln; abgewählte werden nicht berechnet - Einnahmen/Ausgaben je Monat als Balkenpaare mit Saldolinie, aufgesetzt auf den Summenbericht statt auf eine eigene Abfrage - Meine Ausgaben als Ring auf der obersten Kategorieebene - Offene Vorgänge aus allen Modulen Phase 5 – Online-Banking - nemiah/php-fints als Fork auf Codeberg, psr/log direkt eingebaut: die Anwendung hängt an keinem fremden Update-Zyklus - PIN AES-256-GCM-verschlüsselt; Schlüssel aus APP_KEY oder aus data/schluessel/app_key, den der Entrypoint einmalig erzeugt - TAN-Dialog über mehrere Requests (FinTs::persist plus serialisierte Aktion in der Sitzung) – ein wartender Prozess wäre mit php-fpm der falsche Weg - Abgleich statt Direktbuchung: verbinden, übernehmen oder verwerfen - Regeln mit vier Vergleichsarten, Betragsgrenzen und Split-Schema Phase 6 – Wertpapiere - Depotbuchung und Geldbuchung als zwei Seiten eines Geschäfts; betrag ist der Bruttowert, Nebenkosten stehen daneben - Einstand nach gleitendem Durchschnitt, realisierte Gewinne, Erträge - Kursabruf über Leeway oder FMP, täglicher Lauf per Cron - QIF-Import für !Type:Invst Dabei behoben: Der Import buchte den Geldfluss jedes Wertpapiergeschäfts als Abgang – auch bei Verkäufen und Dividenden; und er erkannte das Verrechnungskonto nicht, wenn dem Konto im L-Feld eine Kategorie vorangeht (bei Verkäufen also immer). Phase 7 – Nebenmodule und Zahlungsverkehr - Buchungsvorlagen inklusive QIF-Import, Splits werden mitskaliert - Regelmäßige Buchungen mit Fälligkeitslauf, Finanzkalender, Erinnerungen - Adressen mit IBAN-Prüfung, Verträge mit Kündigungsfrist, Sparziele - Kredite mit gerechnetem Tilgungsplan - Überweisungen über FinTS; die Buchung entsteht erst nach Annahme durch die Bank. Die pain.001-Nachricht erzeugt SepaXml selbst Nebenbei: .dockerignore ergänzt (ohne sie brach der Build an data/mariadb ab), PlatzhalterController entfernt, zwei Inline-Handler beseitigt, die die Content-Security-Policy ohnehin blockierte. 888 PHP-Prüfungen und 45 E2E-Tests grün. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.8 KiB
Wertpapiere und Depots
Ein Depot ist ein Konto der Kontoart Depot. Was darin liegt, steht nicht in
buchungen, sondern in depot_buchungen – dort gehören Stückzahl und Kurs dazu, und der
Saldo ist keine Summe von Beträgen, sondern der bewertete Bestand.
Zwei Seiten je Geschäft
Jedes Wertpapiergeschäft erzeugt bis zu zwei Datensätze:
- die Depotbuchung mit Stück, Kurs, Gebühren und Steuern,
- die Geldbuchung auf dem Verrechnungskonto – eine gewöhnliche Buchung, die im Kontoblatt steht wie jede andere.
Verbunden sind sie über buchung_id. So bleibt das Girokonto stimmig, ohne dass
Kontoblätter Stückzahlen führen müssten. Wird die Depotbuchung gelöscht, geht die
Geldbuchung mit; sie hat ohne das Geschäft keinen Sinn.
Ein- und Auslieferungen rühren kein Konto an und haben deshalb keine Geldbuchung.
Was in welchem Feld steht
betrag ist der Bruttowert: Stück × Kurs, bei Dividenden der Bruttoertrag. Gebühren
und Steuern stehen daneben, nicht darin. Daraus folgt der Geldfluss:
| Vorgang | Verrechnungskonto |
|---|---|
| Kauf | −(Betrag + Gebühren + Steuern) |
| Verkauf | +(Betrag − Gebühren − Steuern) |
| Dividende | +(Betrag − Steuern) |
Am echten Export nachgerechnet: Ein Verkauf über 4 × 797,00 € mit 15,37 € Gebühren und
69,46 € Steuern ergibt 3.103,17 € Gutschrift – genau der Wert, den das QIF im Feld $
nennt. Diese Trennung ist nötig, damit der Einstand die Nebenkosten genau einmal
enthält.
stueck trägt die Richtung: Zugänge positiv, Abgänge negativ, Dividenden null.
Einstand nach gleitendem Durchschnitt
Bei jedem Kauf steigt der Einstand um Kaufpreis samt Gebühren, bei jedem Verkauf sinkt er anteilig um den bis dahin durchschnittlichen Stückpreis. So rechnet auch der FinanzManager, und die Frage, welches Stück verkauft wurde, stellt sich gar nicht.
Der realisierte Gewinn eines Verkaufs ist Erlös minus Kosten minus anteiligem Einstand.
Für die Steuererklärung gilt in Deutschland FIFO. Maßgeblich ist dort die Abrechnung der Bank – diese Übersicht ersetzt sie nicht.
Vollständig verkaufte Positionen verschwinden aus der Bestandsliste; ihr realisierter Gewinn zählt weiter mit.
Kurse
Ein Kurs je Wertpapier und Tag. Mehr Auflösung braucht eine Vermögensübersicht nicht, und die Freikontingente der Kursdienste geben nicht mehr her.
Ohne Kurs wird nicht bewertet: Die Position zeigt „kein Kurs“ und fällt aus der Wertsumme; die Übersicht sagt ausdrücklich, dass sie unvollständig ist. Der Einstand als Ersatzwert wäre bequem, verstellte aber den Blick.
Kursabruf
Services\Kursabruf kennt zwei Anbieter (siehe Aktienkurse.md):
- Leeway.tech – 50 Abrufe/Tag, kennt ISINs direkt
- Financial Modeling Prep – 250 Abrufe/Tag
Beide arbeiten in zwei Schritten: ISIN → Kürzel, Kürzel → Kurs. Das gefundene Kürzel wird am Wertpapier gespeichert, damit der erste Schritt künftig entfällt – das halbiert den Verbrauch. Abgerufen wird nur für Papiere mit Bestand, und nur, wenn für heute noch kein Kurs vorliegt.
Anbieter und Schlüssel stehen im Einstellungsdialog unter Wertpapiere. Der tägliche Lauf gehört in einen Cron-Eintrag:
docker compose exec -u www-data php php scripts/kursabruf.php
Das Skript bricht ab, solange der automatische Abruf in den Einstellungen nicht eingeschaltet ist – ein vergessener Cron-Eintrag kostet so kein Kontingent. Der Knopf auf der Wertpapierseite arbeitet unabhängig davon.
Die Feldnamen der Antworten werden nachsichtig gelesen (close, price, last …): Die
Dienste benennen sie unterschiedlich und gelegentlich um. Der API-Schlüssel steht in der
Adresse und wird vor jedem Logeintrag maskiert.
QIF-Import (!Type:Invst)
Der Import legt Wertpapier, Depotbuchung und Geldbuchung in einem Zug an. Zwei Eigenheiten des Formats:
- Das
L-Feld trägt bei Wertpapiergeschäften mehr als sonst. Dem Verrechnungskonto kann eine Kategorie vorangehen:LKursgewinne:Realisierte Gewinne|[Verrechnungskonto]. Gelesen wird deshalb nur der Teil hinter dem letzten senkrechten Strich. - Das Feld
Oführt zwölf Beträge. Sicher zugeordnet sind Position 4 (Provision) und 10 (fremde Spesen) – beides Gebühren. Alles Übrige sind Abzüge des Fiskus und werden zu „Steuern“ zusammengefasst. Damit fällt keine Position heraus, ohne dass jede einzeln gedeutet werden müsste.
Fehlt der Kurs – bei Dividenden immer –, wird der Bruttobetrag aus der Gutschrift plus den Abzügen zurückgerechnet.
DivIn und DivAus landen beide auf „dividende“; die ursprüngliche Bezeichnung bleibt in
vorgang_qif erhalten, weil die Zuordnung nicht in jedem Fall umkehrbar ist.
Dabei behoben: Bis Phase 5 buchte der Import den Geldfluss jedes
Wertpapiergeschäfts als Abgang – auch bei Verkäufen und Dividenden. Das QIF nennt im Feld
$ immer einen positiven Betrag; die Richtung steckt allein im Vorgang. Verrechnungskonten
von Depots wiesen dadurch zu niedrige Salden aus.
Kontenübersicht
Depots erscheinen dort mit ihrem bewerteten Bestand, nicht mit einem Buchungssaldo. Der Anfangssaldo bleibt dabei: Führt ein Depotkonto eine Barreserve, steht sie dort.
Damit ist die Voraussetzung erfüllt, um die Summe der Kontostände mit dem FinanzManager zu
vergleichen (PLAN.md, Kapitel 7) – sobald Kurse für alle Positionen vorliegen.
Tests
tests/17_WertpapiereTest.php – Wiederfinden über ISIN, WKN und Name samt Nachtragen
fehlender Felder; Bestand und Einstand über mehrere Käufe; Geldseite mit richtigem
Vorzeichen; Verkauf mit anteiligem Einstand und realisiertem Gewinn; Dividende ohne
Bestandsänderung; fehlende Kurse; Veräußerungsrechnung über die Historie hinweg; der
QIF-Import eines echten Ausschnitts (Kauf, Dividende, Verkauf) inklusive Idempotenz;
Löschen samt Geldbuchung.