Beancount (ein Plain-Text-Werkzeug für doppelte Buchführung) und Fava (seine Weboberfläche) sind hochgradig erweiterbar und skriptbar. Ihr Design ermöglicht es dir, Finanzaufgaben zu automatisieren, eigene Berichte zu erstellen und Warnungen per Python-Skript einzurichten. Mit den Worten eines Nutzers: „Ich mag es sehr, meine Daten in einem so praktischen Format zu haben, und ich mag es, dass ich Dinge nach Herzenslust automatisieren kann. Es gibt keine API wie eine Datei auf deiner Festplatte; sie lässt sich leicht integrieren." Diese Anleitung führt durch die Erstellung skriptbarer Workflows – von anfängerfreundlicher Automatisierung bis hin zu fortgeschrittenen Fava-Plugins.
Erkunde ein Live-Beispiel-Ledger:
Starte mit der bea Kommandozeile
Bevor du Python schreibst, prüfe, ob bea die Aufgabe bereits erledigt. Es validiert das Ledger, führt BQL-Abfragen aus, erzeugt die vier Finanzberichte und importiert Bankexporte, und das globale --json verwandelt jeden dieser Vorgänge in einen parsebaren Envelope, den deine Shell in jq weiterleiten kann. Seine Exit-Codes sind der Vertrag, auf den ein geplanter Job verzweigt, sodass cron oder CI überhaupt kein Loader-Skript benötigen. Siehe Buchhaltung mit bea automatisieren für die Zielauflösung, den Envelope und die Exit-Code-Verzweigung, und komm hierher zurück, wenn du eine eigene Berechnung brauchst, die die CLI nicht bereitstellt.
Einstieg: Beancount als Python-Skript ausführen
Für die folgenden eigenen Python-Skripte installiere die Skripting-Bibliotheken (pip install beancount beanquery beangulp). Die Workflows des bea-Befehls verwenden stattdessen die verwaltete Engine; folge dem CLI-Schnellstart, um sie zu installieren. Da Beancount in Python geschrieben ist, kannst du es als Bibliothek in deinen eigenen Skripten verwenden. Die folgenden Skripte wurden mit Beancount 3.2.3, beanquery 0.2.0 und beangulp 0.2.0 ausgeführt. Der allgemeine Ansatz ist:
-
Lade dein Beancount-Ledger: Verwende den Loader von Beancount, um die
.beancount-Datei in Python-Objekte zu parsen. Zum Beispiel:from beancount import loader entries, errors, options = loader.load_file("myledger.beancount") if errors: for error in errors: print(error) raise SystemExit(1)Der Loader gibt Einträge und Fehler gemeinsam zurück. Eine unausgeglichene oder ungültige Datei gibt trotzdem Einträge zurück, also prüfe
errorsund brich ab, bevor du den Daten vertraust. Alle deine Konten, Transaktionen und Salden sind nun im Code zugänglich. -
Nutze die Beancount Query Language (BQL): Anstatt manuell zu iterieren, kannst du SQL-ähnliche Abfragen auf den Daten ausführen. Abfragen leben im separaten Paket
beanquery. In Beancount 3.2.3 gibt es kein Modulbeancount.query. Um zum Beispiel die Gesamtausgaben pro Monat zu erhalten, verbinde die geladenen Einträge und führe die Abfrage direkt aus:import beanquery conn = beanquery.connect("beancount:", entries=entries, errors=errors, options=options) cur = conn.execute( "SELECT year, month, sum(position) WHERE account ~ 'Expenses' GROUP BY year, month" ) for row in cur.fetchall(): print(row)Dies nutzt beanquery zur Aggregation der Daten. Es ist dieselbe Engine hinter
bea query, aber hier rufst du sie in einem Skript auf. Das vermeidet, in einer Schleife einen externen Befehl aufzurufen. -
Richte eine Projektstruktur ein: Organisiere deine Skripte neben deinem Ledger. Ein übliches Layout ist, Verzeichnisse für Importer (zum Abrufen/Parsen externer Daten), reports oder queries (für Analyses-kripte) und documents (zum Speichern heruntergeladener Auszüge) zu haben. Zum Beispiel hält ein Nutzer:
importers/– eigene Python-Importskripte (mit Tests),queries/– Skripte zur Berichtserstellung (ausführbar viapython3 queries/...),documents/– heruntergeladene Bank-CSVs/PDFs, nach Konto organisiert.
Mit diesem Setup kannst du Skripte manuell ausführen (z. B. python3 queries/cash_flow.py) oder sie planen (via cron oder einen Task-Runner), um deinen Workflow zu automatisieren.
Automatisierung von Abstimmungsaufgaben
Abstimmung (Reconciliation) bedeutet, sicherzustellen, dass dein Ledger mit externen Aufzeichnungen (Kontoauszügen, Kreditkartenabrechnungen usw.) übereinstimmt. Beancounts Plain-Text-Ledger und Python-API machen es möglich, einen Großteil dieses Prozesses zu automatisieren.
Importieren und Abgleichen von Transaktionen (Einsteiger)
Für Anfänger ist der empfohlene Ansatz, Importer aus dem separaten beangulp-Paket zu verwenden. Beancount 3 hat das v2-Ingest-Modul und seinen Extraktionsbefehl entfernt. Du schreibst eine kleine Python-Klasse, die beangulp.Importer unterklassifiziert, um ein gegebenes Format (CSV, OFX, PDF usw.) zu parsen und Transaktionen zu erzeugen. Registriere sie in einem kurzen Ingest-Skript und führe sie dann über bea ingest in der verwalteten Engine aus:
- Schreibe einen Importer (eine Python-Klasse mit den Methoden
identify(),account()undextract()) für das CSV-Format deiner Bank. - Füge ein Ingest-Skript hinzu, das deine Importer registriert.
bea ingestführt die Befehleidentify,extractundarchivedes Skripts aus. Ein Workflow führt zum Beispielextractfür alle Dateien in~/Downloadsaus und gibt Transaktionen in eine temporäre Datei aus. - Prüfe manuell und kopiere Transaktionen aus der temporären Datei in dein Haupt-Ledger, dann führe
bea checkaus, um sicherzustellen, dass die Salden übereinstimmen.
Ein minimales Beispiel: eine statement.csv mit den Spalten date,description,amount, geparst von diesem Importer (checking_importer.py):
import csv
import datetime
from beancount.core import data
from beancount.core.amount import Amount
from beancount.core.number import D
import beangulp
class CheckingImporter(beangulp.Importer):
def identify(self, filepath: str) -> bool:
return filepath.endswith("statement.csv")
def account(self, filepath: str) -> str:
return "Assets:Bank:Checking"
def extract(self, filepath: str, existing):
entries = []
with open(filepath, newline="") as f:
for row in csv.DictReader(f):
date = datetime.date.fromisoformat(row["date"])
amount = Amount(D(row["amount"]), "USD")
meta = data.new_metadata(filepath, 0)
entries.append(
data.Transaction(
meta, date, "*", None, row["description"],
data.EMPTY_SET, data.EMPTY_SET, [
data.Posting("Expenses:Food:Groceries", amount,
None, None, None, None),
data.Posting("Assets:Bank:Checking",
Amount(-amount.number, "USD"),
None, None, None, None),
]))
return entriesDas Ingest-Skript (ingest.py) verdrahtet ihn:
from checking_importer import CheckingImporter
from beangulp import Ingest
ingest = Ingest([CheckingImporter()])
if __name__ == "__main__":
ingest()Führe es gegen eine heruntergeladene Datei aus. Für eine lokale CSV sind keine Zugangsdaten erforderlich. Installiere zuerst die Systembibliothek libmagic. Der einmalige Enable-Befehl lädt Beangulp in die verwaltete Engine herunter:
bea engine enable beangulp
bea ingest identify --config ingest.py statement.csv
bea ingest extract --config ingest.py statement.csv -o new.beancountidentify meldet checking_importer.CheckingImporter für die Datei. extract schreibt die Transaktionen im Beancount-Format:
2024-01-08 * "Grocery Store"
Expenses:Food:Groceries 120.00 USD
Assets:Bank:Checking -120.00 USDPrüfe new.beancount, kopiere die Einträge in dein Haupt-Ledger und führe bea check aus.
Du musst keinen Importer schreiben, um einen einzelnen Auszug umzuwandeln. Füge die Datei in den CSV-zu-Beancount-Konverter ein oder nutze OFX & QIF zu Beancount für .ofx-, .qfx- und .qif-Downloads. Beide laufen vollständig in deinem Browser, sodass der Auszug deinen Rechner nie verlässt.
Obwohl dieser Prozess noch einen Prüfschritt beinhaltet, ist ein Großteil der stumpfen Arbeit des Parsens und Formatierens von Einträgen automatisiert. Importer-Skripte können auch automatisch Kategorien zuweisen und sogar Salden-Assertions (Zusicherungen über erwartete Salden) setzen, um Abweichungen zu erkennen. Nach dem Import könntest du zum Beispiel eine Zeile wie 2025-04-30 balance Assets:Bank:Checking 1234.56 USD haben, die den Schlusssaldo zusichert. Wenn du bea check ausführst, wird Beancount überprüfen, ob all diese Saldenzusicherungen korrekt sind, und Fehler melden, wenn Transaktionen fehlen oder doppelt vorhanden sind. Das ist eine Best Practice: Generiere automatisch Saldenzusicherungen für jeden Auszugszeitraum, damit der Computer nicht abgestimmte Unterschiede für dich findet.
Benutzerdefinierte Abstimmungsskripte (Fortgeschritten)
Für mehr Kontrolle kannst du ein eigenes Python-Skript schreiben, um die Transaktionsliste einer Bank (CSV oder via API) mit deinen Ledger-Einträgen zu vergleichen:
- Lies die externen Daten: Parse die CSV-Datei der Bank mit Pythons
csv-Modul (oder Pandas). Normalisiere die Daten in eine Liste von Transaktionen, z. B. jeweils mit Datum, Betrag und Beschreibung. - Lade Ledger-Transaktionen: Verwende
loader.load_filewie zuvor gezeigt, um alle Ledger-Einträge zu erhalten. Filtere diese Liste auf das Konto von Interesse (z. B. dein Girokonto) und vielleicht den Datumsbereich des Auszugs. - Vergleiche und finde Abweichungen:
- Prüfe für jede externe Transaktion, ob ein identischer Eintrag im Ledger existiert (Abgleich nach Datum und Betrag, vielleicht Beschreibung). Wenn nicht gefunden, markiere sie als „neu" und gib sie möglicherweise als Beancount-formatierte Transaktion zur Prüfung aus.
- Umgekehrt identifiziere alle Ledger-Einträge in diesem Konto, die nicht in der externen Quelle erscheinen – das könnten Erfassungsfehler oder Transaktionen sein, die die Bank noch nicht verbucht hat.
- Gib die Ergebnisse aus: Drucke einen Bericht oder erstelle ein neues
.beancount-Snippet mit den fehlenden Transaktionen.
Ein Community-Skript namens reconcile.py macht genau das: Gegeben eine Beancount-Datei und eine Eingabe-CSV, gibt es eine Liste neuer Transaktionen aus, die importiert werden sollten, sowie alle bestehenden Ledger-Buchungen, die nicht in der Eingabe sind (möglicherweise ein Zeichen für Fehlklassifizierung). Mit einem solchen Skript kann die monatliche Abstimmung so einfach sein wie das Ausführen und anschließende Anhängen der vorgeschlagenen Transaktionen an dein Ledger. Ein Beancount-Nutzer merkt an, dass er „jeden Monat einen Abstimmungsprozess für alle Konten durchführt" und eine wachsende Sammlung von Python-Code verwendet, um einen Großteil der manuellen Arbeit beim Importieren und Abstimmen von Daten zu eliminieren.
Tipp: Nutze während der Abstimmung Beancounts Werkzeuge für Genauigkeit:
- Verwende Saldenzusicherungen wie erwähnt, um automatisierte Prüfungen der Kontosalden zu haben.
- Verwende bei Bedarf die
pad-Direktive, die automatisch Ausgleichseinträge für kleinere Rundungsdifferenzen einfügen kann (mit Vorsicht verwenden). - Schreibe Unit-Tests für deinen Importer oder deine Abstimmungslogik (Beancount bietet Test-Helfer). Ein Workflow bestand zum Beispiel darin, eine Beispiel-CSV zu nehmen, fehlschlagende Tests mit erwarteten Transaktionen zu schreiben und dann den Importer zu implementieren, bis alle Tests bestanden. Das stellt sicher, dass dein Importskript für verschiedene Fälle korrekt funktioniert.
Eigene Berichte und Zusammenfassungen erstellen
Während Fava viele Standardberichte bietet (Gewinn- und Verlustrechnung, Bilanz usw.), kannst du mit Skripten eigene Berichte erstellen. Diese können von einfachen Konsolenausgaben bis hin zu reich formatierten Dateien oder Diagrammen reichen.
Abfrage von Daten für Berichte (Anfänger)
Auf grundlegender Ebene kannst du die Beancount Query Language (BQL) verwenden, um Zusammenfassungsdaten zu erhalten und sie auszugeben oder zu speichern. Zum Beispiel:
-
Cash-Flow-Zusammenfassung: Verwende eine Abfrage, um den Netto-Cashflow zu berechnen. „Cashflow" könnte als Veränderung des Saldos bestimmter Konten über einen Zeitraum definiert werden. Mit BQL könntest du Folgendes tun:
SELECT year, month, sum(position) WHERE account ~ 'Income' OR account ~ 'Expenses' GROUP BY year, monthDies verrechnet alle Einnahme- und Ausgabenbuchungen pro Monat. Filtere mit
~und einem regulären Ausdruck:LIKEist in beanquery 0.2.0 ein Syntaxfehler. Buchungen tragenposition, nichtamount. Jede Zeile enthält ein Inventory, sodass jede Währung separat aufgeführt wird, statt umgerechnet zu werden. Einnahmen kommen negativ und Ausgaben positiv an. Du könntest dies überbea queryoder über die zuvor gezeigte beanquery-Python-API ausführen und dann das Ergebnis formatieren. -
Kategorie-Ausgabenbericht: Fasse die Gesamtausgaben pro Kategorie ab:
SELECT account, sum(position) WHERE account ~ 'Expenses' GROUP BY account ORDER BY sum(position) ASCDies ergibt eine Tabelle der Ausgaben nach Kategorie. Jede Summe ist ein Inventory in ihrer ursprünglichen Währung. Umschließe das Aggregat nicht mit
round(): Es gibt keine Funktionround(inventory, int), sodassround(sum(position), 2)nicht kompiliert. Du kannst mehrere Abfragen in einem Skript ausführen und die Ergebnisse als Text, CSV oder sogar JSON zur weiteren Verarbeitung ausgeben.
Ein Nutzer fand es „trivial", Finanzdaten mit Fava oder mit Skripten zu analysieren, und nannte, dass er ein Python-Skript verwendet, um Daten über die Query Language aus Beancount zu ziehen und sie dann in einen Pandas-DataFrame zu überführen, um einen eigenen Bericht zu erstellen. Du könntest zum Beispiel mit einer Abfrage Monatssummen abrufen und dann mit Pandas/Matplotlib ein Cashflow-Diagramm über die Zeit zeichnen. Die Kombination aus BQL und Data-Science-Bibliotheken ermöglicht es dir, Berichte jenseits dessen zu erstellen, was Fava standardmäßig bietet.
Erweiterte Berichterstellung (Diagramme, Performance usw.)
Für fortgeschrittenere Anforderungen können deine Skripte Kennzahlen wie die Anlageperformance berechnen oder visuelle Ausgaben erzeugen:
-
Anlageperformance (IRR/XIRR): Da dein Ledger alle Cashflows enthält (Käufe, Verkäufe, Dividenden), kannst du die Portfoliorenditen berechnen. Du könntest zum Beispiel ein Skript schreiben, das Transaktionen deiner Anlagekonten filtert und dann den Internal Rate of Return berechnet. Es gibt Bibliotheken (oder Formeln), um den IRR aus Cashflow-Daten zu berechnen. Einige von der Community entwickelte Fava-Erweiterungen (wie PortfolioSummary oder fava_investor) machen genau das und berechnen den IRR und andere Kennzahlen für Anlageportfolios. Als Skript könntest du eine IRR-Funktion (aus NumPy oder deine eigene) auf die Reihe von Einzahlungen/Abhebungen plus Endwert anwenden.
-
Mehrperiodische oder eigene Kennzahlen: Möchtest du einen Bericht über deine Sparquote (Verhältnis von Ersparnissen zu Einkommen) pro Monat? Ein Python-Skript kann das Ledger laden, alle Einnahmenkonten und alle Ausgabenkonten summieren und dann Ersparnisse = Einnahmen - Ausgaben und den Prozentsatz berechnen. Das könnte eine schöne Tabelle oder sogar einen HTML-/Markdown-Bericht für deine Unterlagen ausgeben.
-
Visualisierung: Du kannst Diagramme außerhalb von Fava erzeugen. Verwende zum Beispiel
matplotliboderaltairin einem Skript, um ein Diagramm Nettovermögen über die Zeit aus Ledger-Daten zu erstellen. Da das Ledger alle historischen Salden enthält (oder du sie durch Iteration über Einträge aufbauen kannst), kannst du Zeitreihendiagramme erstellen. Speichere diese Diagramme als Bilder oder interaktives HTML. (Wenn du In-App-Visualisierungen bevorzugst, siehe den Abschnitt zu Fava-Erweiterungen unten, um Diagramme innerhalb von Fava hinzuzufügen.)
Ausgabeoptionen: Entscheide, wie der Bericht geliefert wird:
- Für eine einmalige Analyse kann das Drucken auf den Bildschirm oder das Speichern in eine CSV-/Excel-Datei ausreichen.
- Für Dashboards ziehe in Betracht, eine HTML-Datei mit den Daten zu erzeugen (möglicherweise mit einer Templating-Bibliothek wie Jinja2 oder einfach durch Schreiben von Markdown), die du im Browser öffnen kannst.
- Du kannst auch mit Jupyter Notebooks für eine interaktive Berichtsumgebung integrieren, obwohl das eher zum Erkunden als zur Automatisierung dient.
Auslösen von Warnungen aus Ihrem Hauptbuch
Eine weitere leistungsstarke Nutzung skriptbarer Workflows ist das Einrichten von Warnungen basierend auf Bedingungen in deinen Finanzdaten. Da dein Ledger regelmäßig aktualisiert wird (und zukünftige Posten wie anstehende Rechnungen oder Budgets enthalten kann), kannst du es mit einem Skript scannen und über wichtige Ereignisse benachrichtigt werden.
Warnungen bei niedrigem Kontostand
Um Überziehungen zu vermeiden oder einen Mindestsaldo zu halten, möchtest du vielleicht eine Warnung, wenn ein Konto (z. B. Giro- oder Sparkonto) unter einen Schwellenwert fällt. So kannst du das umsetzen:
-
Ermittle die aktuellen Salden: Berechne nach dem Laden von
entriesüber den Loader den neuesten Saldo der Konten von Interesse. Du kannst dies tun, indem du Buchungen aggregierst oder eine Abfrage verwendest. Verwende zum Beispiel eine BQL-Abfrage für den Saldo eines bestimmten Kontos:SELECT sum(position) WHERE account = 'Assets:Bank:Checking'Dies gibt den aktuellen Saldo dieses Kontos zurück (Summe all seiner Buchungen). Alternativ kannst du Beancounts interne Funktionen verwenden, um eine Bilanz zu erstellen. Zum Beispiel:
from beancount.core import realization tree = realization.realize(entries) acct = realization.get_or_create(tree, "Assets:Bank:Checking") balance = acct.balance # an Inventory of commoditiesÜbergib nur die Einträge: Der zweite Parameter ist
min_accounts, nicht die Options-Map. Extrahiere dann den numerischen Wert (z. B. gibtbalance.get_currency_units('USD')den Decimal-Betrag in USD zurück). Wie ein Abfrage-Aggregat hält der Saldo jede Währung separat. Für die meisten Fälle ist die Verwendung der Abfrage jedoch einfacher. -
Prüfe den Schwellenwert: Vergleiche den Saldo mit deinem vordefinierten Limit. Wenn darunter, löse eine Warnung aus.
-
Löse die Benachrichtigung aus: Dies könnte so einfach sein wie das Drucken einer Warnung auf die Konsole, aber für echte Warnungen könntest du eine E-Mail oder Push-Benachrichtigung senden. Du kannst dich mit E-Mail (via
smtplib) oder einem Dienst wie IFTTT oder Slacks Webhook-API integrieren, um die Warnung zu pushen. Zum Beispiel:if balance < 1000: send_email("Low balance alert", f"Account XYZ balance is {balance}")(Implementiere
send_emailmit deinen E-Mail-Server-Details.)
Wenn du dieses Skript täglich ausführst (via Cron-Job oder Windows Task Scheduler), erhältst du proaktive Warnungen. Da es das Ledger verwendet, kann es alle Transaktionen berücksichtigen, einschließlich derer, die du gerade hinzugefügt hast.
Anstehende Zahlungstermine
Wenn du Beancount verwendest, um Rechnungen oder Fristen zu verfolgen, kannst du zukünftige Zahlungen markieren und Skripte dich erinnern lassen. Zwei Möglichkeiten, anstehende Verpflichtungen in Beancount darzustellen:
-
Events: Beancount unterstützt eine
event-Direktive für beliebige datierte Notizen. Zum Beispiel:2025-05-10 event "BillDue" "Mortgage payment due"Dies beeinflusst keine Salden, zeichnet aber ein Datum mit einem Label auf. Ein Skript kann
entriesnachEvent-Einträgen durchsuchen, bei denenEvent.type == "BillDue"(oder ein beliebiger eigener Typ deiner Wahl) und prüfen, ob das Datum innerhalb von, sagen wir, den nächsten 7 Tagen ab heute liegt. Wenn ja, löse eine Warnung aus (E-Mail, Benachrichtigung oder sogar ein Popup). -
Zukünftige Transaktionen: Manche Leute erfassen zukünftig datierte Transaktionen (nachdatiert) für Dinge wie geplante Zahlungen. Diese erscheinen erst in den Salden, wenn das Datum vergeht (es sei denn, du führst Berichte per zukünftigem Datum aus). Ein Skript kann nach Transaktionen suchen, die in der nahen Zukunft datiert sind, und sie auflisten.
Mit diesen kannst du ein „Tickler"-Skript erstellen, das beim Ausführen eine Liste von bald fälligen Aufgaben oder Rechnungen ausgibt. Integriere eine API wie Google Calendar oder einen Task-Manager, wenn du dort automatisch Erinnerungen erstellen möchtest.
Anomalieerkennung
Über bekannte Schwellenwerte oder Daten hinaus kannst du eigene Warnungen für ungewöhnliche Muster skripten. Wenn zum Beispiel eine normalerweise monatliche Ausgabe nicht aufgetreten ist (vielleicht hast du vergessen, eine Rechnung zu bezahlen), oder wenn die Ausgaben einer Kategorie diesen Monat ungewöhnlich hoch sind, könnte dein Skript dies markieren. Dies umfasst typischerweise das Abfragen aktueller Daten und den Vergleich mit der Historie (was ein fortgeschrittenes Thema sein könnte – möglicherweise unter Einsatz von Statistik oder ML).
In der Praxis verlassen sich viele Nutzer auf die Abstimmung, um Anomalien (unerwartete Transaktionen) zu erkennen. Wenn du Bankbenachrichtigungen erhältst (wie E-Mails für jede Transaktion), könntest du diese mit einem Skript parsen und automatisch zu Beancount hinzufügen oder zumindest überprüfen, ob sie erfasst sind. Ein Enthusiast konfigurierte sogar seine Bank so, dass sie Transaktionswarnungs-E-Mails sendet, mit dem Plan, sie automatisch zu parsen und an das Ledger anzuhängen. Diese Art ereignisgesteuerter Warnungen kann sicherstellen, dass keine Transaktion unerfasst bleibt.
Erweiterung von Fava mit benutzerdefinierten Plugins und Ansichten
Fava ist bereits durch sein Erweiterungssystem skriptbar. Wenn du möchtest, dass deine Automatisierung oder Berichte sich direkt in die Weboberfläche integrieren, kannst du eine Fava-Erweiterung (auch Plugin genannt) in Python schreiben.
Wie Fava-Erweiterungen funktionieren: Eine Erweiterung ist ein Python-Modul, das eine Klasse definiert, die von fava.ext.FavaExtensionBase erbt. Du registrierst sie in deiner Beancount-Datei über eine Custom-Option. Wenn du zum Beispiel eine Datei myextension.py mit einer Klasse MyAlerts(FavaExtensionBase) hast, kannst du sie aktivieren, indem du zu deinem Ledger hinzufügst:
1970-01-01 custom "fava-extension" "myextension"Wenn Fava lädt, importiert es dieses Modul und initialisiert deine Klasse MyAlerts.
Erweiterungen können mehrere Dinge tun:
- Hooks: Sie können sich in Ereignisse im Lebenszyklus von Fava einklinken. Zum Beispiel wird
after_load_file()nach dem Laden des Ledgers aufgerufen. Du könntest dies nutzen, um Prüfungen auszuführen oder Daten vorzuberechnen. Wenn du die Niedrigsaldo-Prüfung innerhalb von Fava implementieren möchtest, könnteafter_load_fileüber Kontosalden iterieren und vielleicht Warnungen speichern (obwohl deren Anzeige in der UI etwas mehr Arbeit erfordern könnte, wie das Auslösen eines FavaAPIError oder die Verwendung von Javascript, um eine Benachrichtigung anzuzeigen). - Eigene Berichte/Seiten: Wenn deine Erweiterungsklasse ein Attribut
report_titlesetzt, fügt Fava eine neue Seite in der Seitenleiste dafür hinzu. Du stellst dann ein Template (HTML/Jinja2) für den Inhalt dieser Seite bereit. So erstellst du völlig neue Ansichten, wie ein Dashboard oder eine Zusammenfassung, die Fava standardmäßig nicht hat. Die Erweiterung kann alle Daten sammeln, die sie braucht (du kannst aufself.ledgerzugreifen, das alle Einträge, Salden usw. enthält) und dann das Template rendern.
Zum Beispiel fügt die eingebaute Erweiterung portfolio_list in Fava eine Seite hinzu, die deine Portfoliopositionen auflistet. Community-Erweiterungen gehen weiter:
- Dashboards: Das Plugin fava-dashboards ermöglicht das Definieren eigener Diagramme und Panels (mit Bibliotheken wie Apache ECharts). Es liest eine YAML-Konfiguration von auszuführenden Abfragen, führt sie über Beancount aus und erzeugt eine dynamische Dashboard-Seite in Fava. Im Wesentlichen verbindet es Beancount-Daten und eine JavaScript-Diagrammbibliothek, um interaktive Visualisierungen zu erzeugen.
- Portfolioanalyse: Die Erweiterung PortfolioSummary (von Nutzern beigesteuert) berechnet Anlagezusammenfassungen (Gruppierung von Konten, Berechnung des IRR usw.) und zeigt sie in Favas UI an.
- Transaktionsprüfung: Eine weitere Erweiterung, fava-review, hilft bei der Überprüfung von Transaktionen über die Zeit (z. B. um sicherzustellen, dass du keine Belege verpasst hast).
Um selbst eine einfache Erweiterung zu erstellen, beginne mit dem Unterklassifizieren von FavaExtensionBase. Eine minimale Erweiterung, die eine Seite hinzufügt, könnte zum Beispiel so aussehen:
from fava.ext import FavaExtensionBase
class HelloReport(FavaExtensionBase):
report_title = "Hello World"
def __init__(self, ledger, config):
super().__init__(ledger, config)
# any initialization, perhaps parse config if provided
def after_load_file(self):
# (optional) run after ledger is loaded
print("Ledger loaded with", len(self.ledger.entries), "entries")Wenn du dies in hello.py ablegst und custom "fava-extension" "hello" zu deinem Ledger hinzufügst, würde Fava eine neue Seite „Hello World" anzeigen (du bräuchtest außerdem eine Template-Datei HelloReport.html in einem Unterordner templates, um den Seiteninhalt zu definieren, es sei denn, die Erweiterung verwendet nur Hooks). Das Template kann Daten verwenden, die du an die Erweiterungsklasse anhängst. Fava verwendet Jinja2-Templates, sodass du deine Daten in diesem Template in eine HTML-Tabelle oder ein Diagramm rendern könntest.
Hinweis: Favas Erweiterungssystem ist leistungsstark, gilt aber als „instabil" (Änderungen vorbehalten). Es erfordert einige Vertrautheit mit Webentwicklung (HTML/JS), wenn du eigene Seiten erstellst. Wenn dein Ziel einfach ist, Skripte oder Analysen auszuführen, könnte es einfacher sein, sie als externe Skripte zu behalten. Verwende Fava-Erweiterungen, wenn du eine maßgeschneiderte In-App-Erfahrung für deinen Workflow möchtest.
Integration von Drittanbieter-APIs und Daten
Einer der Vorteile skriptbarer Workflows ist die Fähigkeit, externe Daten einzubinden. Hier sind gängige Integrationen:
Für gehostete Bewertungspreise bietet Live Prices verwaltete Includes ohne ein geplantes Skript zum Abrufen von Preisen. Wähle unterstützte Asset-Paare und eine Quotierungswährung im Picker. Die untenstehenden lokalen dateibasierten Workflows bleiben nützlich für Upstream-Beancount, Fava und reproduzierbare Berichte. Eine verwaltete Aktualisierung erzeugt keinen Git-Commit in deinem Ledger.
-
Wechselkurse & Rohstoffe: Upstream-Beancount ruft Preise nicht selbst ab, bietet aber eine
price-Direktive, damit du Kurse lieferst. Du kannst das Abrufen dieser Preise automatisieren. Ein Skript kann zum Beispiel eine API (Yahoo Finance, Alpha Vantage usw.) für den neuesten Wechselkurs oder Aktienkurs abfragen und einen Preiseintrag an dein Ledger anhängen:2025-04-30 price BTC 30000 USD 2025-04-30 price EUR 1.10 USDEs gibt Werkzeuge wie
bea price, unterstützt von Beanprice in der verwalteten Engine, die tägliche Kurse abrufen und sie im Beancount-Format ausgeben. Du könntest es einmalig mitbea engine enable beanpriceaktivieren und dannbea price main.beancountjede Nacht planen, um eine Include-Dateiprices.beancountzu aktualisieren. Oder verwende Python: z. B. mit der Bibliothekrequests, um eine API aufzurufen. Beancounts Dokumentation schlägt vor, dass du für öffentlich gehandelte Vermögenswerte „etwas Code aufrufen kannst, der Preise herunterlädt und die Direktiven für dich ausschreibt." Mit anderen Worten: Lass ein Skript die Suche durchführen und dieprice-Zeilen einfügen, statt dies manuell zu tun. -
Aktienportfolio-Daten: Ähnlich wie bei Wechselkursen kannst du APIs integrieren, um detaillierte Aktiendaten oder Dividenden abzurufen. Zum Beispiel kann die Yahoo Finance API (oder Community-Bibliotheken wie
yfinance) historische Daten für ein Ticker-Symbol abrufen. Ein Skript könnte dein Ledger mit monatlicher Preishistorie für jede Aktie aktualisieren, die du besitzt, was genaue historische Berichte über den Marktwert ermöglicht. Einige eigene Erweiterungen (wie fava_investor) rufen sogar Preisdaten zur Anzeige on the fly ab, aber am einfachsten ist es, Preise regelmäßig in das Ledger zu importieren. -
Banking-APIs (Open Banking/Plaid): Statt CSVs herunterzuladen, kannst du APIs verwenden, um Transaktionen automatisch abzurufen. Dienste wie Plaid aggregieren Bankkonten und ermöglichen programmatischen Zugriff auf Transaktionen. In einem fortgeschrittenen Setup könntest du ein Python-Skript haben, das die Plaid-API verwendet, um täglich neue Transaktionen abzurufen und sie in einer Datei zu speichern (oder direkt in das Ledger zu importieren). Ein Power-User baute ein System, bei dem Plaid in seine Import-Pipeline einfließt, wodurch seine Bücher nahezu automatisch wurden. Er merkt an, dass „nichts dich davon abhält, dich für die Plaid-API anzumelden und dasselbe lokal zu tun" – d. h. du kannst ein lokales Skript schreiben, um Bankdaten zu erhalten, und dann deine Beancount-Importer-Logik verwenden, um sie in Ledger-Einträge zu parsen. Einige Regionen haben Open-Banking-APIs von Banken; diese könnten ähnlich genutzt werden.
-
Andere APIs: Du könntest Budgetierungswerkzeuge integrieren (geplante Budgets exportieren, um sie mit den Ist-Werten in Beancount zu vergleichen) oder eine OCR-API verwenden, um Belege zu lesen und sie automatisch mit Transaktionen abzugleichen. Da deine Skripte vollen Zugriff auf das Python-Ökosystem haben, kannst du alles integrieren, von E-Mail-Diensten (zum Senden von Warnungen) über Google Sheets (z. B. ein Sheet mit monatlichen Finanzkennzahlen aktualisieren) bis hin zu Messaging-Apps (sende dir selbst einen Zusammenfassungsbericht via Telegram-Bot).
Wenn du Drittanbieter-APIs verwendest, denke daran, deine Zugangsdaten zu sichern (verwende Umgebungsvariablen oder Konfigurationsdateien für API-Schlüssel) und Fehler (Netzwerkprobleme, API-Ausfälle) in deinen Skripten sauber zu behandeln. Es ist oft ratsam, Daten zwischenzuspeichern (zum Beispiel abgerufene Wechselkurse zu speichern, damit du nicht wiederholt denselben historischen Kurs anforderst).
Best Practices für modulare, wartbare Skripte
Während du skriptbare Workflows aufbaust, halte deinen Code organisiert und robust:
-
Modularität: Teile verschiedene Belange in verschiedene Skripte oder Module auf. Habe zum Beispiel separate Skripte für „Datenimport/Abstimmung" vs. „Berichtserstellung" vs. „Warnungen". Du kannst sogar ein kleines Python-Paket für dein Ledger mit Modulen wie
ledger_import.py,ledger_reports.pyusw. erstellen. Das macht jeden Teil leichter verständlich und testbar. -
Konfiguration: Vermeide hartcodierte Werte. Verwende eine Konfigurationsdatei oder Variablen am Anfang des Skripts für Dinge wie Kontonamen, Schwellenwerte, API-Schlüssel, Datumsbereiche usw. Das macht es einfach, Anpassungen vorzunehmen, ohne den Code tiefgreifend zu bearbeiten. Definiere zum Beispiel
LOW_BALANCE_THRESHOLDS = {"Assets:Bank:Checking": 500, "Assets:Savings": 1000}am Anfang, und dein Warnungsskript kann durch dieses Dict schleifen. -
Testen: Behandle deine Finanzautomatisierung als geschäftskritischen Code – denn das ist sie! Schreibe Tests für komplexe Logik. Beancount bietet einige Test-Helfer (intern für Importer-Tests verwendet), die du nutzen kannst, um Ledger-Eingaben zu simulieren. Auch ohne ausgefeilte Frameworks kannst du eine Dummy-CSV und erwartete Ausgabetransaktionen haben und zusichern, dass dein Importskript die korrekten Einträge erzeugt. Wenn du
pytestverwendest, kannst du diese Tests leicht integrieren (wie Alex Watt es über einenjust test-Befehl tat, der pytest umhüllt). -
Versionskontrolle: Halte dein Ledger und deine Skripte unter Versionskontrolle (git). Das gibt dir nicht nur Backups und Historie, sondern ermutigt dich auch, Änderungen kontrolliert vorzunehmen. Du kannst Releases deiner „Finanzskripte" taggen oder Unterschiede beim Debuggen eines Problems überprüfen. Einige Nutzer verfolgen sogar ihre Finanzunterlagen in Git, um Änderungen über die Zeit zu sehen. Sei nur vorsichtig, sensible Daten (wie rohe Auszugsdateien oder API-Schlüssel) in deinem Repo zu ignorieren.
-
Dokumentation: Dokumentiere deine eigenen Workflows für dein zukünftiges Ich. Eine README in deinem Repository, die erklärt, wie die Umgebung eingerichtet wird, wie jedes Skript ausgeführt wird und was jedes tut, wird nach Monaten von unschätzbarem Wert sein. Kommentiere auch deinen Code, insbesondere jede nicht offensichtliche Buchhaltungslogik oder API-Interaktion.
-
Wartung von Fava-Plugins: Wenn du eine Fava-Erweiterung schreibst, halte sie einfach. Fava könnte sich ändern, also sind kleinere Erweiterungen mit gezielter Funktionalität leichter zu aktualisieren. Vermeide es, zu viel Logik zu duplizieren – verwende Beancounts Query-Engine oder vorhandene Hilfsfunktionen, wann immer möglich, statt Berechnungen hart zu codieren, die empfindlich auf Ledger-Änderungen reagieren könnten.
-
Sicherheit: Da deine Skripte sensible Daten verarbeiten und sich mit externen Diensten verbinden können, behandle sie mit Sorgfalt. Lege keine API-Schlüssel offen und ziehe in Betracht, deine Automatisierung auf einer sicheren Maschine auszuführen. Wenn du eine gehostete Lösung oder Cloud verwendest (wie das Planen von GitHub Actions oder einen Server zum Ausführen von Fava), stelle sicher, dass deine Ledger-Daten im Ruhezustand verschlüsselt sind und dass du mit den Datenschutzimplikationen einverstanden bist.
Wenn du diese Praktiken befolgst, stellst du sicher, dass dein Workflow zuverlässig bleibt, auch während sich deine Finanzen (und die Werkzeuge selbst) weiterentwickeln. Du möchtest Skripte, die du Jahr für Jahr mit minimalen Anpassungen wiederverwenden kannst.
Fazit
Beancount und Fava bieten eine leistungsstarke, flexible Plattform für technisch versierte Nutzer, um ihre persönliche Finanzverfolgung vollständig anzupassen. Durch das Schreiben von Python-Skripten kannst du mühsame Aufgaben wie die Abstimmung von Auszügen automatisieren, reichhaltige, auf deine Bedürfnisse zugeschnittene Berichte erstellen und mit rechtzeitigen Warnungen deine Finanzen im Griff behalten. Wir haben eine Reihe von Beispielen von einfach bis fortgeschritten behandelt – beginnend mit einfachen Abfragen und CSV-Importen und übergehend zu vollwertigen Fava-Plugins und externen API-Integrationen. Während du diese umsetzt, fang einfach an und baue schrittweise auf. Selbst ein paar kleine Automatisierungsskripte können Stunden Arbeit sparen und die Genauigkeit enorm verbessern. Und denke daran: Weil alles Plain-Text und Python ist, hast du die volle Kontrolle – dein Finanzsystem wächst mit dir und passt sich deinen spezifischen Bedürfnissen an. Fröhliches Skripten!
Quellen: Die oben genannten Techniken stammen aus der Beancount-Dokumentation und Community-Erfahrungen. Zur weiterführenden Lektüre siehe Beancounts offizielle Docs, Community-Guides und Blogs sowie das Awesome Beancount-Repository für Links zu nützlichen Plugins und Werkzeugen.