Aller au contenu principal

Comment les scripts Python automatisent Beancount et Fava

Beancount et Fava restent scriptables : utilisez Python pour automatiser rapports, soldes et flux de travail personnalisés sur votre grand livre.

Beancount (un outil de comptabilité en partie double en texte brut) et Fava (son interface web) sont hautement extensibles et scriptables. Leur conception vous permet d'automatiser des tâches financières, de générer des rapports personnalisés et de configurer des alertes en écrivant des scripts Python. Selon les mots d'un utilisateur, « J'aime beaucoup avoir mes données dans un format aussi pratique, et j'aime pouvoir automatiser les choses à ma guise. Il n'y a pas d'API comme un fichier sur votre disque ; c'est facile à intégrer. » Ce guide vous guidera à travers la création de flux de travail scriptables—de l'automatisation pour débutants aux plugins Fava avancés.

Explorez un exemple de grand livre en direct :

Ouvrir Example Ledger dans un nouvel onglet

Commencez avec la commande bea

Avant d'écrire du Python, vérifiez si bea fait déjà le travail. Il valide le grand livre, exécute des requêtes BQL, produit les quatre rapports financiers et importe les exports bancaires, et le --json global transforme chacun d'eux en une enveloppe analysable que votre shell peut rediriger vers jq. Ses codes de sortie sont le contrat sur lequel un travail planifié se base, donc cron ou CI n'a besoin d'aucun script de chargement. Voir automatiser la tenue de livres avec bea pour la résolution de cible, l'enveloppe et les codes de sortie, et revenez ici lorsque vous avez besoin d'un calcul personnalisé que la CLI n'expose pas.

Pour commencer : exécuter Beancount comme script Python

Pour les scripts Python personnalisés ci-dessous, installez les bibliothèques de script (pip install beancount beanquery beangulp). Les flux de travail de la commande bea utilisent le moteur géré à la place ; suivez le démarrage rapide CLI pour l'installer. Puisque Beancount est écrit en Python, vous pouvez l'utiliser comme bibliothèque dans vos propres scripts. Les scripts ci-dessous ont été exécutés avec Beancount 3.2.3, beanquery 0.2.0 et beangulp 0.2.0. L'approche générale est :

  • Chargez votre grand livre Beancount : Utilisez le chargeur de Beancount pour analyser le fichier .beancount en objets Python. Par exemple :

    from beancount import loader
    entries, errors, options = loader.load_file("myledger.beancount")
    if errors:
        for error in errors:
            print(error)
        raise SystemExit(1)

    Le chargeur renvoie les entrées et les erreurs ensemble. Un fichier non équilibré ou invalide renvoie quand même des entrées, alors vérifiez errors et arrêtez-vous avant de faire confiance aux données. Tous vos comptes, transactions et soldes sont maintenant accessibles dans le code.

  • Tirez parti du langage de requête Beancount (BQL) : Au lieu d'itérer manuellement, vous pouvez exécuter des requêtes de type SQL sur les données. Les requêtes vivent dans le package séparé beanquery. Il n'y a pas de module beancount.query dans Beancount 3.2.3. Par exemple, pour obtenir les dépenses totales par mois, connectez les entrées chargées et exécutez la requête directement :

    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)

    Cela utilise beanquery pour agréger les données. C'est le même moteur derrière bea query, mais ici vous l'appelez dans un script. Cela évite d'appeler une commande externe dans une boucle.

  • Mettez en place une structure de projet : Organisez vos scripts à côté de votre grand livre. Une disposition courante consiste à avoir des répertoires pour importateurs (pour récupérer/analyser des données externes), rapports ou requêtes (pour les scripts d'analyse), et documents (pour stocker les relevés téléchargés). Par exemple, un utilisateur conserve :

    • importers/ – scripts d'importation Python personnalisés (avec tests),
    • queries/ – scripts pour générer des rapports (exécutables via python3 queries/...),
    • documents/ – CSV/PDF bancaires téléchargés organisés par compte.

    Avec cette configuration, vous pouvez exécuter des scripts manuellement (par ex. python3 queries/cash_flow.py) ou les planifier (via cron ou un exécuteur de tâches) pour automatiser votre flux de travail.

Automatisation des tâches de rapprochement

Le rapprochement signifie s'assurer que votre grand livre correspond aux enregistrements externes (relevés bancaires, rapports de carte de crédit, etc.). Le grand livre en texte brut et l'API Python de Beancount permettent d'automatiser une grande partie de ce processus.

Importation et correspondance des transactions (Débutant)

Pour les débutants, l'approche recommandée est d'utiliser les importateurs du package séparé beangulp. Beancount 3 a supprimé le module d'ingestion v2 et sa commande extract. Vous écrivez une petite classe Python qui sous-classe beangulp.Importer pour analyser un format donné (CSV, OFX, PDF, etc.) et produire des transactions. Enregistrez-la dans un court script d'ingestion, puis exécutez-la via bea ingest dans le moteur géré :

  • Écrivez un importateur (une classe Python avec les méthodes identify(), account() et extract()) pour le format CSV de votre banque.
  • Ajoutez un script d'ingestion qui enregistre vos importateurs. bea ingest exécute les commandes identify, extract et archive du script. Par exemple, un flux de travail exécute extract sur tous les fichiers de ~/Downloads et sort les transactions vers un fichier temporaire.
  • Examinez et copiez manuellement les transactions du fichier temporaire dans votre grand livre principal, puis exécutez bea check pour vous assurer que les soldes se rapprochent.

Un exemple minimal : un statement.csv avec les colonnes date,description,amount, analysé par cet importateur (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 entries

Le script d'ingestion (ingest.py) le connecte :

from checking_importer import CheckingImporter
from beangulp import Ingest
 
ingest = Ingest([CheckingImporter()])
 
if __name__ == "__main__":
    ingest()

Exécutez-le contre un fichier téléchargé. Aucune information d'identification n'est nécessaire pour un CSV local. Installez d'abord la bibliothèque système libmagic. La commande d'activation unique télécharge Beangulp dans le moteur géré :

bea engine enable beangulp
bea ingest identify --config ingest.py statement.csv
bea ingest extract --config ingest.py statement.csv -o new.beancount

identify signale checking_importer.CheckingImporter pour le fichier. extract écrit les transactions au format Beancount :

2024-01-08 * "Grocery Store"
  Expenses:Food:Groceries   120.00 USD
  Assets:Bank:Checking     -120.00 USD

Examinez new.beancount, copiez les entrées dans votre grand livre principal, puis exécutez bea check.

Ignorez l'importateur pour un cas unique

Vous n'avez pas besoin d'écrire un importateur pour convertir un seul relevé. Collez le fichier dans le convertisseur CSV vers Beancount, ou utilisez OFX & QIF vers Beancount pour les téléchargements .ofx, .qfx et .qif. Les deux fonctionnent entièrement dans votre navigateur, donc le relevé ne quitte jamais votre machine.

Bien que ce processus implique encore une étape de révision, une grande partie du travail fastidieux d'analyse et de formatage des entrées est automatisée. Les scripts d'importateur peuvent également attribuer automatiquement des catégories et même définir des assertions de solde (déclarations de soldes attendus) pour détecter les écarts. Par exemple, après l'importation, vous pourriez avoir une ligne comme 2025-04-30 balance Assets:Bank:Checking 1234.56 USD qui affirme le solde de clôture. Lorsque vous exécutez bea check, Beancount vérifiera que toutes ces assertions de solde sont correctes, et signalera toute erreur si des transactions sont manquantes ou dupliquées. C'est une bonne pratique : générer automatiquement des assertions de solde pour chaque période de relevé afin de laisser l'ordinateur repérer les différences non rapprochées pour vous.

Scripts de rapprochement personnalisés (Intermédiaire)

Pour plus de contrôle, vous pouvez écrire un script Python personnalisé pour comparer la liste des transactions d'une banque (CSV ou via API) avec vos entrées de grand livre :

  1. Lisez les données externes : Analysez le fichier CSV de la banque en utilisant le module csv de Python (ou Pandas). Normalisez les données en une liste de transactions, par ex. chacune avec une date, un montant et une description.
  2. Chargez les transactions du grand livre : Utilisez loader.load_file comme montré précédemment pour obtenir toutes les entrées du grand livre. Filtrez cette liste pour le compte concerné (par ex. votre compte courant) et peut-être la période de dates du relevé.
  3. Comparez et trouvez les écarts :
  • Pour chaque transaction externe, vérifiez si une entrée identique existe dans le grand livre (correspondance par date et montant, peut-être description). Si ce n'est pas trouvé, marquez-la comme « nouvelle » et éventuellement sortez-la comme transaction au format Beancount pour révision.
  • Inversement, identifiez toutes les entrées du grand livre dans ce compte qui n'apparaissent pas dans la source externe – cela pourrait être des erreurs de saisie ou des transactions qui n'ont pas encore été débitées par la banque.
  1. Sortez les résultats : Imprimez un rapport ou créez un nouvel extrait .beancount avec les transactions manquantes.

Par exemple, un script communautaire appelé reconcile.py fait exactement cela : étant donné un fichier Beancount et un CSV d'entrée, il imprime une liste de nouvelles transactions à importer, ainsi que toutes les écritures de grand livre existantes qui ne sont pas dans l'entrée (potentiellement un signe de mauvaise classification). Avec un tel script, le rapprochement mensuel peut être aussi simple que de l'exécuter puis d'ajouter les transactions suggérées à votre grand livre. Un utilisateur de Beancount note qu'il « fait un processus de rapprochement sur tous les comptes chaque mois » et utilise une collection croissante de code Python pour éliminer une grande partie du travail manuel dans l'importation et le rapprochement des données.

Astuce : Pendant le rapprochement, tirez parti des outils de Beancount pour la précision :

  • Utilisez les assertions de solde comme mentionné, pour avoir des vérifications automatisées sur les soldes des comptes.
  • Utilisez la directive pad si souhaité, qui peut insérer automatiquement des écritures d'équilibrage pour les petites différences d'arrondi (à utiliser avec prudence).
  • Écrivez des tests unitaires pour votre importateur ou votre logique de rapprochement (Beancount fournit des aides de test). Par exemple, un flux de travail impliquait de prendre un CSV d'échantillon, d'écrire des tests échouant avec les transactions attendues, puis d'implémenter l'importateur jusqu'à ce que tous les tests passent. Cela garantit que votre script d'importation fonctionne correctement pour divers cas.

Génération de rapports et résumés personnalisés

Bien que Fava fournisse de nombreux rapports standard (État des résultats, Bilan, etc.), vous pouvez créer des rapports personnalisés à l'aide de scripts. Ceux-ci peuvent aller de simples sorties console à des fichiers riches formatés ou des graphiques.

Interrogation des données pour les rapports (Débutant)

À un niveau de base, vous pouvez utiliser le langage de requête Beancount (BQL) pour obtenir des données récapitulatives et les imprimer ou les sauvegarder. Par exemple :

  • Résumé du flux de trésorerie : Utilisez une requête pour calculer le flux de trésorerie net. Le « flux de trésorerie » pourrait être défini comme le changement de solde de certains comptes sur une période. En utilisant BQL, vous pourriez faire :

    SELECT year, month, sum(position)
    WHERE account ~ 'Income' OR account ~ 'Expenses'
    GROUP BY year, month

    Cela nettoie tous les postings de revenus et dépenses par mois. Filtrez avec ~ et une expression régulière : LIKE est une erreur de syntaxe dans beanquery 0.2.0. Les postings portent position, pas amount. Chaque ligne contient un Inventory, donc chaque devise est listée séparément au lieu d'être convertie. Les revenus arrivent négatifs et les dépenses positives. Vous pourriez exécuter cela via bea query ou via l'API Python beanquery montrée précédemment, puis formater le résultat.

  • Rapport de dépenses par catégorie : Interrogez les dépenses totales par catégorie :

    SELECT account, sum(position)
    WHERE account ~ 'Expenses'
    GROUP BY account
    ORDER BY sum(position) ASC

    Cela produit un tableau des dépenses par catégorie. Chaque total est un Inventory dans sa devise d'origine. N'enveloppez pas l'agrégat dans round() : il n'y a pas de fonction round(inventory, int), donc round(sum(position), 2) ne compile pas. Vous pouvez exécuter plusieurs requêtes dans un script et sortir les résultats sous forme de texte, CSV, ou même JSON pour un traitement ultérieur.

Un utilisateur a trouvé « trivial » d'analyser des données financières avec Fava ou avec des scripts, citant qu'il utilise un script Python pour extraire des données de Beancount via le langage de requête, puis les mettre dans un DataFrame Pandas pour préparer un rapport personnalisé. Par exemple, vous pourriez récupérer des totaux mensuels avec une requête, puis utiliser Pandas/Matplotlib pour tracer un graphique de flux de trésorerie au fil du temps. La combinaison de BQL et des bibliothèques de science des données vous permet de créer des rapports au-delà de ce que Fava offre par défaut.

Rapports avancés (graphiques, performance, etc.)

Pour des besoins plus avancés, vos scripts peuvent calculer des métriques comme la performance des investissements ou créer des sorties visuelles :

  • Performance des investissements (IRR/XIRR) : Puisque votre grand livre contient tous les flux de trésorerie (achats, ventes, dividendes), vous pouvez calculer les taux de rendement du portefeuille. Par exemple, vous pourriez écrire un script qui filtre les transactions de vos comptes d'investissement, puis calcule le taux de rendement interne. Il existe des bibliothèques (ou formules) pour calculer l'IRR à partir des données de flux de trésorerie. Certaines extensions Fava communautaires (comme PortfolioSummary ou fava_investor) font exactement cela, calculant l'IRR et d'autres métriques pour les portefeuilles d'investissement. En tant que script, vous pourriez utiliser une fonction IRR (de NumPy ou la vôtre) sur la série de contributions/retraits plus la valeur finale.

  • Métriques multi-périodes ou personnalisées : Voulez-vous un rapport de votre taux d'épargne (ratio de l'épargne sur les revenus) chaque mois ? Un script Python peut charger le grand livre, additionner tous les comptes de revenus et tous les comptes de dépenses, puis calculer l'épargne = revenus - dépenses et le pourcentage. Cela pourrait sortir un joli tableau ou même générer un rapport HTML/Markdown pour vos archives.

  • Visualisation : Vous pouvez générer des graphiques en dehors de Fava. Par exemple, utilisez matplotlib ou altair dans un script pour créer un graphique de valeur nette au fil du temps, en utilisant les données du grand livre. Parce que le grand livre a tous les soldes historiques (ou vous pouvez les accumuler en itérant les entrées), vous pouvez produire des tracés de séries temporelles. Sauvegardez ces graphiques en tant qu'images ou HTML interactif. (Si vous préférez les visuels dans l'application, voir la section sur les extensions Fava ci-dessous pour ajouter des graphiques dans Fava.)

Options de sortie : Décidez comment livrer le rapport :

  • Pour une analyse ponctuelle, imprimer à l'écran ou sauvegarder dans un fichier CSV/Excel peut suffire.
  • Pour des tableaux de bord, envisagez de générer un fichier HTML avec les données (éventuellement en utilisant une bibliothèque de modèles comme Jinja2 ou même simplement en écrivant du Markdown) que vous pouvez ouvrir dans un navigateur.
  • Vous pouvez également intégrer des Jupyter Notebooks pour un environnement de rapport interactif, bien que cela soit plus pour l'exploration que pour l'automatisation.

Déclenchement d'alertes depuis votre grand livre

Une autre utilisation puissante des flux de travail scriptables est la configuration d'alertes basées sur des conditions dans vos données financières. Parce que votre grand livre est mis à jour régulièrement (et peut inclure des éléments datés futurs comme des factures à venir ou des budgets), vous pouvez le scanner avec un script et être notifié des événements importants.

Avertissements de solde de compte faible

Pour éviter les découverts ou maintenir un solde minimum, vous pourriez vouloir une alerte si un compte (par ex. courant ou épargne) tombe sous un seuil. Voici comment vous pouvez implémenter cela :

  1. Déterminez les soldes actuels : Après avoir chargé entries via le chargeur, calculez le dernier solde des comptes concernés. Vous pouvez le faire en agrégeant les postings ou en utilisant une requête. Par exemple, utilisez une requête BQL pour le solde d'un compte spécifique :

    SELECT sum(position) WHERE account = 'Assets:Bank:Checking'

    Cela retourne le solde actuel de ce compte (somme de tous ses postings). Alternativement, utilisez les fonctions internes de Beancount pour construire un bilan. Par exemple :

    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

    Passez uniquement les entrées : le deuxième paramètre est min_accounts, pas la carte d'options. Ensuite, extrayez la valeur numérique (par ex. balance.get_currency_units('USD') retourne le montant Decimal en USD). Comme un agrégat de requête, le solde garde chaque devise séparément. Cependant, utiliser la requête est plus simple pour la plupart des cas.

  2. Vérifiez le seuil : Comparez le solde à votre limite prédéfinie. Si en dessous, déclenchez une alerte.

  3. Déclenchez la notification : Cela pourrait être aussi simple que d'imprimer un avertissement à la console, mais pour de vraies alertes, vous pourriez envoyer un email ou une notification push. Vous pouvez intégrer l'email (via smtplib) ou un service comme IFTTT ou l'API webhook de Slack pour pousser l'alerte. Par exemple :

    if balance < 1000:
        send_email("Low balance alert", f"Account XYZ balance is {balance}")

    (Implémentez send_email avec les détails de votre serveur email.)

En exécutant ce script quotidiennement (via cron ou le Planificateur de tâches Windows), vous obtiendrez des avertissements proactifs. Parce qu'il utilise le grand livre, il peut considérer toutes les transactions, y compris celles que vous venez d'ajouter.

Échéances de paiement à venir

Si vous utilisez Beancount pour suivre les factures ou les échéances, vous pouvez marquer les paiements futurs et avoir des scripts pour vous rappeler. Deux façons de représenter les obligations à venir dans Beancount :

  • Événements : Beancount prend en charge une directive event pour les notes datées arbitraires. Par exemple :

    2025-05-10 event "BillDue" "Mortgage payment due"

    Cela n'affecte pas les soldes mais enregistre une date avec une étiquette. Un script peut scanner entries pour les entrées EventEvent.type == "BillDue" (ou tout type personnalisé que vous choisissez) et vérifier si la date est dans, disons, les 7 prochains jours à partir d'aujourd'hui. Si oui, déclenchez une alerte (email, notification, ou même une popup).

  • Transactions futures : Certaines personnes saisissent des transactions datées futurs (postdatées) pour des choses comme des paiements planifiés. Celles-ci n'apparaîtront pas dans les soldes avant que la date ne passe (sauf si vous exécutez des rapports à des dates futures). Un script peut chercher les transactions datées dans un futur proche et les lister.

En utilisant ces méthodes, vous pourriez créer un script « rappel » qui, lorsqu'il est exécuté, sort une liste de tâches ou de factures dues bientôt. Intégrez une API comme Google Calendar ou un gestionnaire de tâches si vous voulez créer automatiquement des rappels là-bas.

Détection d'anomalies

Au-delà des seuils ou dates connus, vous pouvez scripté des alertes personnalisées pour des modèles inhabituels. Par exemple, si une dépense normalement mensuelle n'a pas eu lieu (peut-être avez-vous oublié de payer une facture), ou si les dépenses d'une catégorie sont anormalement élevées ce mois-ci, votre script pourrait le signaler. Cela implique généralement d'interroger des données récentes et de les comparer à l'historique (ce qui pourrait être un sujet avancé – éventuellement en utilisant des statistiques ou du ML).

En pratique, de nombreux utilisateurs s'appuient sur le rapprochement pour détecter les anomalies (transactions inattendues). Si vous recevez des notifications bancaires (comme des emails pour chaque transaction), vous pourriez les analyser avec un script et les ajouter automatiquement à Beancount, ou au moins vérifier qu'elles sont enregistrées. Un passionné a même configuré sa banque pour envoyer des emails d'alerte de transaction, avec le plan de les analyser et de les ajouter au grand livre automatiquement. Ce type d'alerte pilotée par événement peut garantir que aucune transaction ne reste non enregistrée.

Extension de Fava avec des plugins et vues personnalisés

Fava est déjà scriptable grâce à son système d'extensions. Si vous voulez que votre automatisation ou vos rapports s'intègrent directement dans l'interface web, vous pouvez écrire une extension Fava (aussi appelée plugin) en Python.

Comment fonctionnent les extensions Fava : Une extension est un module Python qui définit une classe héritant de fava.ext.FavaExtensionBase. Vous l'enregistrez dans votre fichier Beancount via une option personnalisée. Par exemple, si vous avez un fichier myextension.py avec une classe MyAlerts(FavaExtensionBase), vous pouvez l'activer en ajoutant à votre grand livre :

1970-01-01 custom "fava-extension" "myextension"

Lorsque Fava se charge, il importera ce module et initialisera votre classe MyAlerts.

Les extensions peuvent faire plusieurs choses :

  • Hooks : Elles peuvent se connecter aux événements du cycle de vie de Fava. Par exemple, after_load_file() est appelé après le chargement du grand livre. Vous pourriez l'utiliser pour exécuter des vérifications ou précalculer des données. Si vous vouliez implémenter la vérification de solde faible dans Fava, after_load_file pourrait itérer sur les soldes des comptes et stocker des avertissements (bien que les afficher à l'interface utilisateur pourrait nécessiter un peu plus de travail, comme lever un FavaAPIError ou utiliser JavaScript pour montrer une notification).
  • Rapports/Pages personnalisés : Si votre classe d'extension définit un attribut report_title, Fava ajoutera une nouvelle page dans la barre latérale pour elle. Vous fournissez ensuite un modèle (HTML/Jinja2) pour le contenu de cette page. C'est ainsi que vous créez des vues entièrement nouvelles, comme un tableau de bord ou un résumé que Fava n'a pas par défaut. L'extension peut rassembler les données dont elle a besoin (vous pouvez accéder à self.ledger qui a toutes les entrées, soldes, etc.) puis rendre le modèle.

Par exemple, l'extension intégrée portfolio_list dans Fava ajoute une page listant vos positions de portefeuille. Les extensions communautaires vont plus loin :

  • Tableaux de bord : Le plugin fava-dashboards permet de définir des graphiques et panneaux personnalisés (en utilisant des bibliothèques comme Apache ECharts). Il lit une configuration YAML de requêtes à exécuter, les exécute via Beancount, et génère une page de tableau de bord dynamique dans Fava. En substance, il relie les données Beancount et une bibliothèque de graphiques JavaScript pour produire des visualisations interactives.
  • Analyse de portefeuille : L'extension PortfolioSummary (contribution utilisateur) calcule des résumés d'investissement (regroupement des comptes, calcul de l'IRR, etc.) et les affiche dans l'interface de Fava.
  • Révision des transactions : Une autre extension, fava-review, aide à réviser les transactions au fil du temps (par ex. pour s'assurer que vous n'avez manqué aucun reçu).

Pour créer une extension simple vous-même, commencez par sous-classer FavaExtensionBase. Par exemple, une extension minimale qui ajoute une page pourrait ressembler à :

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")

Si vous placez cela dans hello.py et ajoutez custom "fava-extension" "hello" à votre grand livre, Fava afficherait une nouvelle page « Hello World » (vous auriez aussi besoin d'un fichier modèle HelloReport.html dans un sous-dossier templates pour définir le contenu de la page, sauf si l'extension n'utilise que des hooks). Le modèle peut utiliser les données que vous attachez à la classe d'extension. Fava utilise des modèles Jinja2, donc vous pourriez rendre vos données dans un tableau HTML ou un graphique dans ce modèle.

Note : Le système d'extensions de Fava est puissant mais considéré comme « instable » (sujet à changement). Il nécessite une certaine familiarité avec le développement web (HTML/JS) si vous créez des pages personnalisées. Si votre objectif est simplement d'exécuter des scripts ou des analyses, il pourrait être plus facile de les garder comme scripts externes. Utilisez les extensions Fava lorsque vous voulez une expérience sur mesure dans l'application pour votre flux de travail.

Intégration d'API et de données tierces

L'un des avantages des flux de travail scriptables est la capacité de tirer des données externes. Voici des intégrations courantes :

  • Taux de change et matières premières : Beancount ne récupère pas automatiquement les prix par conception (pour garder les rapports déterministes), mais il fournit une directive Price pour que vous fournissiez les taux. Vous pouvez automatiser la récupération de ces prix. Par exemple, un script peut interroger une API (Yahoo Finance, Alpha Vantage, etc.) pour le dernier taux de change ou le prix d'une action et ajouter une entrée de prix à votre grand livre :

    2025-04-30 price BTC 30000 USD
    2025-04-30 price EUR 1.10 USD

    Il existe des outils comme bea price, soutenus par Beanprice dans le moteur géré, qui récupèrent les cotations quotidiennes et les sortent au format Beancount. Vous pourriez l'activer une fois avec bea engine enable beanprice, puis planifier bea price main.beancount pour qu'il s'exécute chaque nuit afin de mettre à jour un fichier d'inclusion prices.beancount. Ou utilisez Python : par ex., avec la bibliothèque requests pour appeler une API. _La documentation de Beancount suggère que pour les actifs négociés publiquement, vous pouvez « invoquer du code qui téléchargera les prix et écrira les directives pour vous ». _ En d'autres termes, laissez un script faire la recherche et insérer les lignes price, plutôt que de le faire manuellement.

  • Données de portefeuille d'actions : Similaire aux taux de change, vous pouvez intégrer des API pour récupérer des données détaillées sur les actions ou les dividendes. Par exemple, l'API Yahoo Finance (ou des bibliothèques communautaires comme yfinance) peut récupérer des données historiques pour un ticker. Un script pourrait mettre à jour votre grand livre avec l'historique des prix mensuels pour chaque action que vous possédez, permettant des rapports historiques précis de la valeur marchande. Certaines extensions personnalisées (comme fava_investor) tirent même des données de prix à la volée pour l'affichage, mais le plus simple est d'importer régulièrement les prix dans le grand livre.

  • API bancaires (Open Banking/Plaid) : Au lieu de télécharger des CSV, vous pouvez utiliser des API pour récupérer les transactions automatiquement. Des services comme Plaid agrègent les comptes bancaires et permettent un accès programmatique aux transactions. Dans une configuration avancée, vous pourriez avoir un script Python qui utilise l'API de Plaid pour tirer les nouvelles transactions quotidiennement et les sauvegarder dans un fichier (ou les importer directement dans le grand livre). Un utilisateur expérimenté a construit un système où Plaid alimente son pipeline d'importation, rendant ses livres presque automatiques. Ils notent que « rien ne vous empêche de vous inscrire à l'API Plaid et de faire la même chose localement » – c'est-à-dire, vous pouvez écrire un script local pour obtenir les données bancaires, puis utiliser votre logique d'importateur Beancount pour les analyser en entrées de grand livre. Certaines régions ont des API bancaires ouvertes fournies par les banques ; celles-ci pourraient être utilisées de manière similaire.

  • Autres API : Vous pourriez intégrer des outils de budgétisation (exportant des budgets planifiés pour les comparer aux données réelles dans Beancount), ou utiliser une API OCR pour lire les reçus et les faire correspondre automatiquement aux transactions. Parce que vos scripts ont un accès complet à l'écosystème Python, vous pouvez intégrer tout, des services email (pour l'envoi d'alertes) à Google Sheets (par ex. mettre à jour une feuille avec les métriques financières mensuelles) aux applications de messagerie (vous envoyer un rapport récapitulatif via un bot Telegram).

Lorsque vous utilisez des API tierces, n'oubliez pas de sécuriser vos identifiants (utilisez des variables d'environnement ou des fichiers de configuration pour les clés API) et de gérer les erreurs (problèmes de réseau, indisponibilité de l'API) avec élégance dans vos scripts. Il est souvent sage de mettre en cache les données (par exemple, stocker les taux de change récupérés pour ne pas demander le même taux historique à plusieurs reprises).

Bonnes pratiques pour des scripts modulaires et maintenables

Au fur et à mesure que vous construisez des flux de travail scriptables, gardez votre code organisé et robuste :

  • Modularité : Séparez les différentes préoccupations dans différents scripts ou modules. Par exemple, ayez des scripts séparés pour « importation/rapprochement des données » vs « génération de rapports » vs « alertes ». Vous pouvez même créer un petit package Python pour votre grand livre avec des modules comme ledger_import.py, ledger_reports.py, etc. Cela rend chaque partie plus facile à comprendre et à tester.

  • Configuration : Évitez de coder en dur les valeurs. Utilisez un fichier de configuration ou des variables en haut du script pour des choses comme les noms de comptes, seuils, clés API, plages de dates, etc. Cela facilite l'ajustement sans éditer profondément le code. Par exemple, définissez LOW_BALANCE_THRESHOLDS = {"Assets:Bank:Checking": 500, "Assets:Savings": 1000} en haut, et votre script d'alerte peut boucler sur ce dictionnaire.

  • Tests : Traitez votre automatisation financière comme du code critique – parce qu'elle l'est ! Écrivez des tests pour la logique complexe. Beancount fournit quelques aides de test (utilisées en interne pour les tests d'importateur) que vous pouvez exploiter pour simuler des entrées de grand livre. Même sans frameworks sophistiqués, vous pouvez avoir un CSV factice et des transactions de sortie attendues, et affirmer que votre script d'importation produit les bonnes entrées. Si vous utilisez pytest, vous pouvez intégrer ces tests facilement (comme l'a fait Alex Watt via une commande just test enveloppant pytest).

  • Contrôle de version : Gardez votre grand livre et vos scripts sous contrôle de version (git). Cela vous donne non seulement des sauvegardes et un historique, mais encourage à faire des changements de manière contrôlée. Vous pouvez marquer des versions de vos « scripts financiers » ou examiner les différences lors du débogage d'un problème. Certains utilisateurs suivent même leurs enregistrements financiers dans Git pour voir les changements au fil du temps. Assurez-vous simplement d'ignorer les données sensibles (comme les fichiers de relevés bruts ou les clés API) dans votre référentiel.

  • Documentation : Documentez vos flux de travail personnalisés pour le futur vous. Un README dans votre référentiel expliquant comment configurer l'environnement, comment exécuter chaque script et ce que chacun fait sera inestimable après des mois. Commentez également votre code, surtout toute logique comptable non évidente ou interaction API.

  • Maintenance des plugins Fava : Si vous écrivez une extension Fava, gardez-la simple. Fava pourrait changer, donc des extensions plus petites avec des fonctionnalités ciblées sont plus faciles à mettre à jour. Évitez de dupliquer trop de logique – utilisez le moteur de requêtes de Beancount ou les fonctions d'aide existantes autant que possible, plutôt que de coder en dur des calculs qui pourraient être sensibles aux changements du grand livre.

  • Sécurité : Puisque vos scripts peuvent traiter des données sensibles et se connecter à des services externes, traitez-les avec soin. N'exposez pas les clés API, et envisagez d'exécuter votre automatisation sur une machine sécurisée. Si vous utilisez une solution hébergée ou le cloud (comme planifier des actions GitHub ou un serveur pour exécuter Fava), assurez-vous que vos données de grand livre sont chiffrées au repos et que vous êtes à l'aise avec les implications de confidentialité.

En suivant ces pratiques, vous garantissez que votre flux de travail reste fiable même si vos finances (et les outils eux-mêmes) évoluent. Vous voulez des scripts que vous pouvez réutiliser année après année, avec des ajustements minimaux.

Conclusion

Beancount et Fava fournissent une plateforme puissante et flexible pour les utilisateurs férus de technologie afin de personnaliser complètement leur suivi financier personnel. En écrivant des scripts Python, vous pouvez automatiser des tâches fastidieuses comme le rapprochement des relevés, produire des rapports riches adaptés à vos besoins, et rester au courant de vos finances avec des alertes opportunes. Nous avons couvert une gamme d'exemples du basique à l'avancé – en commençant par des requêtes simples et des importations CSV, et en avançant vers des plugins Fava complets et des intégrations API externes. Au fur et à mesure que vous les implémentez, commencez simplement et construisez progressivement. Même quelques petits scripts d'automatisation peuvent économiser des heures de travail et améliorer considérablement la précision. Et rappelez-vous, parce que tout est en texte brut et Python, vous avez un contrôle total – votre système financier grandit avec vous, s'adaptant à vos besoins spécifiques. Bon scripting !

Sources : Les techniques ci-dessus sont tirées de la documentation Beancount et des expériences communautaires. Pour une lecture plus approfondie, voir la documentation officielle de Beancount, les guides et blogs communautaires, et le référentiel Awesome Beancount pour des liens vers des plugins et outils utiles.

Source : https://beancount.io/fr/docs/Solutions/scriptable-workflows