Saltar al contenido principal

Cómo los scripts de Python automatizan Beancount y Fava

Beancount y Fava siguen siendo programables: usa Python para automatizar informes, balances y flujos de trabajo personalizados en tu libro mayor.

Beancount (una herramienta de contabilidad por partida doble en texto plano) y Fava (su interfaz web) son altamente extensibles y programables. Su diseño te permite automatizar tareas financieras, generar informes personalizados y configurar alertas escribiendo scripts de Python. En palabras de un usuario, "realmente me gusta tener mis datos en un formato tan cómodo, y me gusta poder automatizar cosas a mi antojo. No hay API como un archivo en tu disco; es fácil de integrar." Esta guía recorrerá la creación de flujos de trabajo programables—desde la automatización amigable para principiantes hasta plugins avanzados de Fava.

Explora un libro contable de ejemplo en vivo:

Abrir Example Ledger en una pestaña nueva

Comienza con la línea de comandos bea​

Antes de escribir cualquier Python, comprueba si bea ya hace el trabajo. Valida el libro contable, ejecuta consultas BQL, produce los cuatro informes financieros e importa extractos bancarios, y el --json global convierte cada uno de ellos en una envoltura analizable que tu shell puede canalizar hacia jq. Sus códigos de salida son el contrato sobre el que se ramifica un trabajo programado, así que cron o CI no necesitan ningún script cargador en absoluto. Consulta automatizar la contabilidad con bea para la resolución del objetivo, la envoltura y la ramificación por códigos de salida, y vuelve aquí cuando necesites un cálculo personalizado que la CLI no expone.

Comenzando: Ejecutar Beancount como script Python​

Para los scripts personalizados de Python que aparecen a continuación, instala las bibliotecas de scripting (pip install beancount beanquery beangulp). Los flujos de trabajo del comando bea usan en su lugar el motor gestionado; sigue la guía rápida de la CLI para instalarlo. Como Beancount está escrito en Python, puedes usarlo como una biblioteca en tus propios scripts. Los scripts siguientes se ejecutaron con Beancount 3.2.3, beanquery 0.2.0 y beangulp 0.2.0. El enfoque general es:

  • Cargar tu libro contable de Beancount: Usa el cargador de Beancount para analizar el archivo .beancount en objetos de Python. Por ejemplo:

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

    El cargador devuelve entradas y errores juntos. Un archivo desbalanceado o inválido aún devuelve entradas, así que revisa errors y detente antes de confiar en los datos. Todas tus cuentas, transacciones y saldos ahora son accesibles en código.

  • Aprovechar el Lenguaje de Consulta de Beancount (BQL): En lugar de iterar manualmente, puedes ejecutar consultas similares a SQL sobre los datos. Las consultas viven en el paquete separado beanquery. No existe un módulo beancount.query en Beancount 3.2.3. Por ejemplo, para obtener los gastos totales por mes, conecta las entradas cargadas y ejecuta la consulta directamente:

    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)

    Esto usa beanquery para agregar datos. Es el mismo motor detrás de bea query, pero aquí lo llamas en un script. Eso evita invocar un comando externo en un bucle.

  • Configurar una estructura de proyecto: Organiza tus scripts junto a tu libro contable. Una disposición común es tener directorios para importadores (para obtener/analizar datos externos), informes o consultas (para scripts de análisis), y documentos (para almacenar extractos descargados). Por ejemplo, un usuario mantiene:

    • importers/ – scripts de importación personalizados en Python (con pruebas),
    • queries/ – scripts para generar informes (ejecutables mediante python3 queries/...),
    • documents/ – CSV/PDF bancarios descargados, organizados por cuenta.

Con esta configuración, puedes ejecutar los scripts manualmente (p. ej. python3 queries/cash_flow.py) o programarlos (mediante cron o un ejecutor de tareas) para automatizar tu flujo de trabajo.

Automatizando tareas de conciliación​

La conciliación significa asegurarse de que tu libro contable coincide con los registros externos (extractos bancarios, informes de tarjetas de crédito, etc.). El libro contable en texto plano y la API de Python de Beancount hacen posible automatizar gran parte de este proceso.

Importar y hacer correspondencia de transacciones (Principiante)​

Para principiantes, el enfoque recomendado es usar importadores del paquete separado beangulp. Beancount 3 eliminó el módulo de ingesta v2 y su comando extract. Escribes una pequeña clase de Python que hereda de beangulp.Importer para analizar un formato dado (CSV, OFX, PDF, etc.) y producir transacciones. Regístrala en un breve script de ingesta y luego ejecútala a través de bea ingest en el motor gestionado:

  • Escribe un importador (una clase de Python con los métodos identify(), account() y extract()) para el formato CSV de tu banco.
  • Añade un script de ingesta que registre tus importadores. bea ingest ejecuta los comandos identify, extract y archive del script. Por ejemplo, un flujo de trabajo ejecuta extract sobre todos los archivos en ~/Downloads y envía las transacciones a un archivo temporal.
  • Revisa y copia manualmente las transacciones del archivo temporal a tu libro contable principal, luego ejecuta bea check para asegurar que los saldos concilien.

Un ejemplo mínimo: un statement.csv con columnas date,description,amount, analizado por este importador (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

El script de ingesta (ingest.py) lo conecta:

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

Ejecútalo contra un archivo descargado. No se necesitan credenciales para un CSV local. Instala primero la biblioteca del sistema libmagic. El comando de habilitación único descarga Beangulp en el motor gestionado:

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

identify informa checking_importer.CheckingImporter para el archivo. extract escribe las transacciones en formato Beancount:

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

Revisa new.beancount, copia las entradas a tu libro contable principal y ejecuta bea check.

Omite el importador para un caso puntual

No necesitas escribir un importador para convertir un único extracto. Pega el archivo en el conversor de CSV a Beancount, o usa OFX y QIF a Beancount para descargas .ofx, .qfx y .qif. Ambos se ejecutan completamente en tu navegador, así que el extracto nunca sale de tu máquina.

Aunque este proceso todavía incluye un paso de revisión, gran parte del trabajo pesado de analizar y dar formato a las entradas está automatizado. Los scripts de importación también pueden asignar categorías automáticamente e incluso establecer aserciones de saldo (declaraciones de saldos esperados) para detectar discrepancias. Por ejemplo, tras importar, podrías tener una línea como 2025-04-30 balance Assets:Bank:Checking 1234.56 USD que afirma el saldo de cierre. Cuando ejecutas bea check, Beancount verificará que todas estas aserciones de saldo sean correctas, y señalará cualquier error si faltan o se duplican transacciones. Esta es una buena práctica: autogenerar aserciones de saldo para cada período de extracto para que la computadora detecte por ti las diferencias no conciliadas.

Scripts personalizados de conciliación (Intermedio)​

Para más control, puedes escribir un script de Python personalizado que compare la lista de transacciones de un banco (CSV o vía API) con las entradas de tu libro contable:

  1. Leer los datos externos: Analiza el archivo CSV del banco usando el módulo csv de Python (o Pandas). Normaliza los datos en una lista de transacciones, por ejemplo, cada una con una fecha, un importe y una descripción.
  2. Cargar las transacciones del libro contable: Usa loader.load_file como se mostró antes para obtener todas las entradas del libro contable. Filtra esta lista a la cuenta de interés (p. ej. tu cuenta corriente) y quizás al rango de fechas del extracto.
  3. Comparar y encontrar discrepancias:
  • Para cada transacción externa, comprueba si existe una entrada idéntica en el libro contable (coincidiendo por fecha e importe, quizás descripción). Si no se encuentra, márcala como "nueva" y posiblemente envíala como una transacción en formato Beancount para que la revises.
  • A la inversa, identifica cualquier entrada del libro contable en esa cuenta que no aparezca en la fuente externa – estas podrían ser errores de captura o transacciones que aún no se han liquidado en el banco.
  1. Enviar los resultados: Imprime un informe o crea un nuevo fragmento .beancount con las transacciones faltantes.

Como ejemplo, un script de la comunidad llamado reconcile.py hace exactamente esto: dado un archivo Beancount y un CSV de entrada, imprime una lista de nuevas transacciones que deberían importarse, así como cualquier asiento existente del libro contable que no esté en la entrada (posiblemente señal de una clasificación errónea). Con un script así, la conciliación mensual puede ser tan simple como ejecutarlo y luego añadir las transacciones sugeridas a tu libro contable. Un usuario de Beancount señala que "hace un proceso de conciliación de todas las cuentas cada mes" y usa una colección creciente de código Python para eliminar gran parte del trabajo manual en la importación y conciliación de datos.

Consejo: Durante la conciliación, aprovecha las herramientas de Beancount para mayor precisión:

  • Usa aserciones de saldo como se mencionó, para tener comprobaciones automatizadas de los saldos de las cuentas.
  • Usa la directiva pad si lo deseas, que puede insertar automáticamente asientos de compensación para pequeñas diferencias de redondeo (úsala con precaución).
  • Escribe pruebas unitarias para tu importador o tu lógica de conciliación (Beancount ofrece ayudas para pruebas). Por ejemplo, un flujo de trabajo consistió en tomar un CSV de muestra, escribir pruebas fallidas con las transacciones esperadas, y luego implementar el importador hasta que todas las pruebas pasaran. Esto asegura que tu script de importación funcione correctamente en varios casos.

Generación de Informes y Resúmenes Personalizados​

Aunque Fava proporciona muchos informes estándar (Estado de Resultados, Balance General, etc.), puedes crear informes personalizados usando scripts. Estos pueden ir desde simples salidas de consola hasta archivos con formato enriquecido o gráficos.

Consultar datos para informes (Principiante)​

A un nivel básico, puedes usar el Lenguaje de Consulta de Beancount (BQL) para obtener datos de resumen e imprimirlos o guardarlos. Por ejemplo:

  • Resumen de flujo de caja: Usa una consulta para calcular el flujo de caja neto. El "flujo de caja" podría definirse como el cambio en el saldo de ciertas cuentas durante un período. Usando BQL, podrías hacer:

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

    Esto netea todos los asientos de ingresos y gastos por mes. Filtra con ~ y una expresión regular: LIKE es un error de sintaxis en beanquery 0.2.0. Los asientos llevan position, no amount. Cada fila contiene un Inventory, así que cada divisa se lista por separado en lugar de convertirse. Los ingresos llegan negativos y los gastos positivos. Podrías ejecutar esto mediante bea query o vía la API de Python de beanquery mostrada antes, y luego dar formato al resultado.

  • Informe de gastos por categoría: Consulta los gastos totales por categoría:

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

    Esto produce una tabla de gastos por categoría. Cada total es un Inventory en su divisa original. No envuelvas el agregado en round(): no existe una función round(inventory, int), así que round(sum(position), 2) no compila. Puedes ejecutar múltiples consultas en un script y enviar los resultados como texto, CSV o incluso JSON para su posterior procesamiento.

Un usuario consideró "trivial" analizar datos financieros con Fava o con scripts, citando que usa un script de Python para extraer datos de Beancount mediante el Lenguaje de Consulta y luego ponerlos en un DataFrame de Pandas para preparar un informe personalizado. Por ejemplo, podrías obtener totales mensuales con una consulta y luego usar Pandas/Matplotlib para trazar un gráfico de flujo de caja a lo largo del tiempo. La combinación de BQL y bibliotecas de ciencia de datos te permite construir informes más allá de lo que Fava ofrece por defecto.

Reportes avanzados (Gráficos, rendimiento, etc.)​

Para necesidades más avanzadas, tus scripts pueden calcular métricas como el rendimiento de inversiones o crear salidas visuales:

  • Rendimiento de inversiones (IRR/XIRR): Como tu libro contable contiene todos los flujos de caja (compras, ventas, dividendos), puedes calcular las tasas de rendimiento de la cartera. Por ejemplo, podrías escribir un script que filtre las transacciones de tus cuentas de inversión y luego calcule la Tasa Interna de Retorno. Existen bibliotecas (o fórmulas) para calcular la IRR dados los datos de flujos de caja. Algunas extensiones de Fava desarrolladas por la comunidad (como PortfolioSummary o fava_investor) hacen exactamente esto, calculando la IRR y otras métricas para carteras de inversión. Como script, podrías usar una función de IRR (de NumPy o tuya propia) sobre la serie de aportes/retiros más el valor final.

  • Métricas multiperíodo o personalizadas: ¿Quieres un informe de tu tasa de ahorro (proporción de ahorros sobre ingresos) cada mes? Un script de Python puede cargar el libro contable, sumar todas las cuentas de Ingresos y todas las cuentas de Gastos, y luego calcular ahorros = ingresos - gastos y el porcentaje. Esto podría producir una tabla agradable o incluso generar un informe en HTML/Markdown para tus registros.

  • Visualización: Puedes generar gráficos fuera de Fava. Por ejemplo, usa matplotlib o altair en un script para crear un gráfico de patrimonio neto a lo largo del tiempo, usando los datos del libro contable. Como el libro contable tiene todos los saldos históricos (o puedes acumularlos iterando las entradas), puedes producir gráficos de series temporales. Guarda estos gráficos como imágenes o HTML interactivo. (Si prefieres visuales dentro de la aplicación, consulta la sección de extensiones de Fava más abajo para añadir gráficos dentro de Fava.)

Opciones de salida: Decide cómo entregar el informe:

  • Para un análisis puntual, imprimir en pantalla o guardar en un archivo CSV/Excel puede ser suficiente.
  • Para paneles, considera generar un archivo HTML con los datos (posiblemente usando una biblioteca de plantillas como Jinja2 o incluso simplemente escribiendo Markdown) que puedas abrir en un navegador.
  • También puedes integrarte con Jupyter Notebooks para un entorno de informes interactivo, aunque eso es más para exploración que para automatización.

Activación de alertas desde tu libro mayor​

Otro uso potente de los flujos de trabajo programables es configurar alertas basadas en condiciones de tus datos financieros. Como tu libro contable se actualiza con regularidad (y puede incluir elementos con fecha futura, como facturas próximas o presupuestos), puedes escanearlo con un script y recibir notificaciones de eventos importantes.

Advertencias de saldo bajo en cuentas​

Para evitar sobregiros o mantener un saldo mínimo, quizás quieras una alerta si alguna cuenta (p. ej. corriente o ahorros) cae por debajo de un umbral. Aquí tienes cómo implementarlo:

  1. Determinar los saldos actuales: Tras cargar entries mediante el cargador, calcula el saldo más reciente de las cuentas de interés. Puedes hacerlo agregando asientos o usando una consulta. Por ejemplo, usa una consulta BQL para el saldo de una cuenta específica:

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

    Esto devuelve el saldo actual de esa cuenta (suma de todos sus asientos). Alternativamente, usa las funciones internas de Beancount para construir un balance general. Por ejemplo:

    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

    Pasa solo las entradas: el segundo parámetro es min_accounts, no el mapa de opciones. Luego extrae el valor numérico (p. ej. balance.get_currency_units('USD') devuelve el importe Decimal en USD). Como un agregado de consulta, el saldo mantiene cada divisa por separado. Sin embargo, usar la consulta es más simple para la mayoría de los casos.

  2. Comprobar el umbral: Compara el saldo con tu límite predefinido. Si está por debajo, dispara una alerta.

  3. Disparar la notificación: Esto podría ser tan simple como imprimir una advertencia en la consola, pero para alertas reales podrías enviar un correo electrónico o una notificación push. Puedes integrarte con correo electrónico (vía smtplib) o un servicio como IFTTT o la API de webhooks de Slack para enviar la alerta. Por ejemplo:

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

    (Implementa send_email con los detalles de tu servidor de correo.)

Al ejecutar este script a diario (mediante un trabajo cron o el Programador de tareas de Windows), obtendrás advertencias proactivas. Como usa el libro contable, puede considerar todas las transacciones, incluidas las que acabas de añadir.

Vencimientos de Pagos Próximos​

Si usas Beancount para rastrear facturas o plazos, puedes marcar pagos futuros y hacer que los scripts te lo recuerden. Dos formas de representar obligaciones próximas en Beancount:

  • Eventos: Beancount admite una directiva event para notas arbitrarias con fecha. Por ejemplo:

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

    Esto no afecta los saldos, pero registra una fecha con una etiqueta. Un script puede escanear entries en busca de entradas Event donde Event.type == "BillDue" (o cualquier tipo personalizado que elijas) y comprobar si la fecha está dentro de, digamos, los próximos 7 días desde hoy. Si es así, dispara una alerta (correo electrónico, notificación o incluso una ventana emergente).

  • Transacciones futuras: Algunas personas introducen transacciones con fecha futura (posfechadas) para cosas como pagos programados. Estas no aparecerán en los saldos hasta que pase la fecha (a menos que ejecutes informes con fechas futuras). Un script puede buscar transacciones con fecha en el futuro cercano y listarlas.

Usando esto, podrías crear un script "recordatorio" que, al ejecutarse, muestre una lista de tareas o facturas que vencen pronto. Intégrate con una API como Google Calendar o un gestor de tareas si quieres crear recordatorios automáticamente allí.

Detección de Anomalías​

Más allá de umbrales o fechas conocidos, puedes programar alertas personalizadas para patrones inusuales. Por ejemplo, si un gasto normalmente mensual no ha ocurrido (quizás olvidaste pagar una factura), o si el gasto de una categoría es anormalmente alto este mes, tu script podría señalarlo. Esto normalmente implica consultar datos recientes y compararlos con el historial (lo cual podría ser un tema avanzado – posiblemente empleando estadística o ML).

En la práctica, muchos usuarios confían en la conciliación para detectar anomalías (transacciones inesperadas). Si recibes notificaciones bancarias (como correos por cada transacción), podrías analizarlas con un script y añadirlas automáticamente a Beancount, o al menos verificar que estén registradas. Un entusiasta incluso configuró su banco para enviar correos de alerta de transacciones, con el plan de analizarlos y añadirlos automáticamente al libro contable. Este tipo de alerta basada en eventos puede asegurar que ninguna transacción quede sin registrar.

Ampliando Fava con Plugins y Vistas Personalizadas​

Fava ya es programable a través de su sistema de extensiones. Si quieres que tu automatización o tus informes se integren directamente en la interfaz web, puedes escribir una extensión de Fava (también llamada plugin) en Python.

Cómo funcionan las extensiones de Fava: Una extensión es un módulo de Python que define una clase que hereda de fava.ext.FavaExtensionBase. La registras en tu archivo Beancount mediante una opción personalizada. Por ejemplo, si tienes un archivo myextension.py con una clase MyAlerts(FavaExtensionBase), puedes habilitarla añadiendo a tu libro contable:

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

Cuando Fava cargue, importará ese módulo e inicializará tu clase MyAlerts.

Las extensiones pueden hacer varias cosas:

  • Hooks: Pueden engancharse a eventos del ciclo de vida de Fava. Por ejemplo, after_load_file() se llama después de cargar el libro contable. Podrías usar esto para ejecutar comprobaciones o precalcular datos. Si quisieras implementar la comprobación de saldo bajo dentro de Fava, after_load_file podría iterar sobre los saldos de las cuentas y quizás almacenar advertencias (aunque mostrarlas en la interfaz podría requerir algo más de trabajo, como lanzar un FavaAPIError o usar Javascript para mostrar una notificación).
  • Informes/páginas personalizadas: Si tu clase de extensión define un atributo report_title, Fava añadirá una nueva página en la barra lateral para él. Luego proporcionas una plantilla (HTML/Jinja2) para el contenido de esa página. Así es como creas vistas completamente nuevas, como un panel o un resumen que Fava no tiene por defecto. La extensión puede reunir los datos que necesite (puedes acceder a self.ledger, que tiene todas las entradas, saldos, etc.) y luego renderizar la plantilla.

Por ejemplo, la extensión incorporada portfolio_list en Fava añade una página que lista las posiciones de tu cartera. Las extensiones de la comunidad van más allá:

  • Paneles: El plugin fava-dashboards permite definir gráficos y paneles personalizados (usando bibliotecas como Apache ECharts). Lee una configuración YAML de consultas a ejecutar, las ejecuta vía Beancount y genera una página de panel dinámica en Fava. En esencia, une los datos de Beancount y una biblioteca de gráficos de JavaScript para producir visualizaciones interactivas.
  • Análisis de cartera: La extensión PortfolioSummary (aportada por usuarios) calcula resúmenes de inversión (agrupando cuentas, calculando la IRR, etc.) y los muestra en la interfaz de Fava.
  • Revisión de transacciones: Otra extensión, fava-review, ayuda a revisar transacciones a lo largo del tiempo (p. ej. para asegurarte de no haber olvidado ningún recibo).

Para crear tú mismo una extensión simple, empieza heredando de FavaExtensionBase. Por ejemplo, una extensión mínima que añade una página podría verse así:

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 colocaras esto en hello.py y añadieras custom "fava-extension" "hello" a tu libro contable, Fava mostraría una nueva página "Hello World" (también necesitarías un archivo de plantilla HelloReport.html en una subcarpeta templates para definir el contenido de la página, a menos que la extensión solo use hooks). La plantilla puede usar los datos que adjuntes a la clase de extensión. Fava usa plantillas Jinja2, así que podrías renderizar tus datos en una tabla HTML o un gráfico en esa plantilla.

Nota: El sistema de extensiones de Fava es potente pero se considera "inestable" (sujeto a cambios). Requiere cierta familiaridad con el desarrollo web (HTML/JS) si vas a crear páginas personalizadas. Si tu objetivo es simplemente ejecutar scripts o análisis, podría ser más fácil mantenerlos como scripts externos. Usa extensiones de Fava cuando quieras una experiencia adaptada dentro de la aplicación para tu flujo de trabajo.

Integración de APIs de terceros y datos​

Una de las ventajas de los flujos de trabajo programables es la capacidad de incorporar datos externos. Aquí tienes integraciones comunes:

Para precios de valoración alojados, Live Prices ofrece includes gestionados sin un script programado de obtención de precios. Elige pares de activos admitidos y una divisa de cotización en el selector. Los flujos de trabajo locales basados en archivos de abajo siguen siendo útiles para Beancount upstream, Fava e informes reproducibles. Una actualización gestionada no crea un commit de Git en tu libro contable.

  • Tipos de cambio y materias primas: Beancount upstream no obtiene precios por sí mismo, pero proporciona una directiva price para que tú proporciones las cotizaciones. Puedes automatizar la obtención de estos precios. Por ejemplo, un script puede consultar una API (Yahoo Finance, Alpha Vantage, etc.) para el último tipo de cambio o precio de una acción y añadir una entrada de precio a tu libro contable:

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

    Existen herramientas como bea price, respaldada por Beanprice en el motor gestionado, que obtienen cotizaciones diarias y las emiten en formato Beancount. Podrías habilitarla una vez con bea engine enable beanprice, y luego programar bea price main.beancount para ejecutarse cada noche y actualizar un archivo incluido prices.beancount. O usar Python: p. ej., con la biblioteca requests para llamar a una API. La documentación de Beancount sugiere que, para activos cotizados públicamente, puedes "invocar algo de código que descargue precios y escriba las directivas por ti." En otras palabras, deja que un script haga la consulta e inserte las líneas price, en lugar de hacerlo manualmente.

  • Datos de carteras de acciones: De forma similar a los tipos de cambio, puedes integrarte con API para obtener datos detallados de acciones o dividendos. Por ejemplo, la API de Yahoo Finance (o bibliotecas de la comunidad como yfinance) puede recuperar datos históricos de un ticker. Un script podría actualizar tu libro contable con el historial de precios mensuales de cada acción que posees, permitiendo informes históricos precisos del valor de mercado. Algunas extensiones personalizadas (como fava_investor) incluso obtienen datos de precios al vuelo para mostrarlos, pero lo más simple es importar precios al libro contable con regularidad.

  • API bancarias (Open Banking/Plaid): En lugar de descargar CSV, puedes usar API para obtener transacciones automáticamente. Servicios como Plaid agregan cuentas bancarias y permiten el acceso programático a las transacciones. En una configuración avanzada, podrías tener un script de Python que use la API de Plaid para obtener nuevas transacciones a diario y guardarlas en un archivo (o importarlas directamente al libro contable). Un usuario avanzado construyó un sistema donde Plaid alimenta su canal de importación, haciendo sus libros casi automáticos. Señalan que "nada te impide registrarte con la API de Plaid y hacer lo mismo localmente" – es decir, puedes escribir un script local para obtener datos bancarios, y luego usar tu lógica de importación de Beancount para analizarlos en entradas del libro contable. Algunas regiones tienen API de banca abierta proporcionadas por los bancos; esas podrían usarse de manera similar.

  • Otras API: Podrías integrar herramientas de presupuestación (exportando presupuestos planificados para compararlos con los reales en Beancount), o usar una API de OCR para leer recibos y emparejarlos automáticamente con transacciones. Como tus scripts tienen acceso completo al ecosistema de Python, puedes integrar todo, desde servicios de correo electrónico (para enviar alertas) hasta Google Sheets (p. ej. actualizar una hoja con métricas financieras mensuales) o aplicaciones de mensajería (enviarte un informe resumen vía un bot de Telegram).

Cuando uses API de terceros, recuerda asegurar tus credenciales (usa variables de entorno o archivos de configuración para las claves de API) y manejar los errores (problemas de red, caídas de la API) con elegancia en tus scripts. A menudo es prudente almacenar en caché los datos (por ejemplo, guardar los tipos de cambio obtenidos para no solicitar repetidamente el mismo tipo histórico).

Mejores prácticas para scripts modulares y mantenibles​

A medida que construyes flujos de trabajo programables, mantén tu código organizado y robusto:

  • Modularidad: Divide las distintas responsabilidades en scripts o módulos diferentes. Por ejemplo, ten scripts separados para "importación de datos/conciliación" frente a "generación de informes" frente a "alertas". Incluso puedes crear un pequeño paquete de Python para tu libro contable con módulos como ledger_import.py, ledger_reports.py, etc. Esto hace que cada parte sea más fácil de entender y probar.

  • Configuración: Evita codificar valores directamente. Usa un archivo de configuración o variables al inicio del script para cosas como nombres de cuentas, umbrales, claves de API, rangos de fechas, etc. Esto facilita los ajustes sin editar el código en profundidad. Por ejemplo, define LOW_BALANCE_THRESHOLDS = {"Assets:Bank:Checking": 500, "Assets:Savings": 1000} al principio, y tu script de alertas puede recorrer este diccionario.

  • Pruebas: Trata tu automatización financiera como código crítico – ¡porque lo es! Escribe pruebas para la lógica compleja. Beancount proporciona algunas ayudas para pruebas (usadas internamente para probar importadores) que puedes aprovechar para simular entradas del libro contable. Incluso sin frameworks sofisticados, puedes tener un CSV ficticio y las transacciones de salida esperadas, y afirmar que tu script de importación produce las entradas correctas. Si usas pytest, puedes integrar estas pruebas fácilmente (como hizo Alex Watt mediante un comando just test que envuelve pytest).

  • Control de versiones: Mantén tu libro contable y tus scripts bajo control de versiones (git). Esto no solo te da copias de seguridad e historial, sino que te anima a hacer cambios de forma controlada. Puedes etiquetar versiones de tus "scripts financieros" o revisar diferencias al depurar un problema. Algunos usuarios incluso registran sus registros financieros en Git para ver los cambios a lo largo del tiempo. Solo ten cuidado de ignorar los datos sensibles (como archivos de extractos en bruto o claves de API) en tu repositorio.

  • Documentación: Documenta tus flujos de trabajo personalizados para tu yo futuro. Un README en tu repositorio que explique cómo configurar el entorno, cómo ejecutar cada script y qué hace cada uno será invaluable después de que pasen meses. También comenta tu código, especialmente cualquier lógica contable poco obvia o interacción con API.

  • Mantenimiento de plugins de Fava: Si escribes una extensión de Fava, mantenla simple. Fava podría cambiar, así que las extensiones más pequeñas con funcionalidad concreta son más fáciles de actualizar. Evita duplicar demasiada lógica – usa el motor de consultas de Beancount o funciones auxiliares existentes siempre que sea posible, en lugar de codificar cálculos que podrían ser sensibles a los cambios del libro contable.

  • Seguridad: Como tus scripts pueden manejar datos sensibles y conectarse a servicios externos, trátalos con cuidado. No expongas claves de API y considera ejecutar tu automatización en una máquina segura. Si usas una solución alojada o la nube (como programar GitHub Actions o un servidor para ejecutar Fava), asegúrate de que los datos de tu libro contable estén cifrados en reposo y de que te sientas cómodo con las implicaciones de privacidad.

Siguiendo estas prácticas, aseguras que tu flujo de trabajo siga siendo fiable incluso a medida que tus finanzas (y las propias herramientas) evolucionan. Quieres scripts que puedas reutilizar año tras año, con ajustes mínimos.

Conclusión​

Beancount y Fava proporcionan una plataforma potente y flexible para que los usuarios con conocimientos técnicos personalicen por completo su seguimiento de finanzas personales. Escribiendo scripts de Python, puedes automatizar tareas tediosas como conciliar extractos, producir informes enriquecidos adaptados a tus necesidades y mantenerte al día con tus finanzas mediante alertas oportunas. Cubrimos una variedad de ejemplos de básicos a avanzados – empezando con consultas simples e importaciones CSV, y pasando a plugins completos de Fava e integraciones con API externas. A medida que los implementes, empieza simple y ve construyendo gradualmente. Incluso unos pocos scripts de automatización pequeños pueden ahorrar horas de trabajo y mejorar enormemente la precisión. Y recuerda, como todo es texto plano y Python, tienes el control total – tu sistema financiero crece contigo, adaptándose a tus necesidades específicas. ¡Feliz scripting!

Fuentes: Las técnicas anteriores se extraen de la documentación de Beancount y de experiencias de la comunidad. Para más lectura, consulta la documentación oficial de Beancount, guías y blogs de la comunidad, y el repositorio Awesome Beancount para enlaces a plugins y herramientas útiles.

Fuente: https://beancount.io/es/docs/Solutions/scriptable-workflows