Beancount (una herramienta de contabilidad de doble entrada en texto plano) y Fava (su interfaz web) son altamente extensibles y scriptables. Su diseño te permite automatizar tareas financieras, generar informes personalizados y configurar alertas escribiendo scripts en Python. En palabras de un usuario, “Me gusta mucho tener mis datos en un formato tan conveniente, y me gusta poder automatizar las cosas a mi antojo. No hay API como un archivo en tu disco; es fácil de integrar.” Esta guía te guiará a través de la creación de flujos de trabajo scriptables—desde automatizaciones amigables para principiantes hasta plugins avanzados para Fava.
Explora un libro mayor de ejemplo en vivo:
Comienza con la línea de comandos bea
Antes de escribir cualquier Python, verifica si bea ya hace el trabajo. Este valida el libro mayor, ejecuta consultas BQL, produce los cuatro informes financieros e importa exportaciones bancarias, y --json global convierte cada uno de estos en un sobre analizables que tu shell puede canalizar a jq. Sus códigos de salida son el contrato sobre el que se ramifica un trabajo programado, por lo que cron o CI no necesitan ningún script cargador. Consulta automatiza la contabilidad con bea para la resolución de destino, el sobre y la ramificación por código de salida, y regresa aquí cuando necesites un cálculo personalizado que la CLI no exponga.
Comenzando: Ejecutar Beancount como script Python
Para los scripts Python personalizados a continuación, instala las bibliotecas de scripting (pip install beancount beanquery beangulp). Los flujos de trabajo con comandos bea usan el motor gestionado en su lugar; sigue la introducción rápida a la CLI para instalarlo. Dado que Beancount está escrito en Python, puedes utilizarlo como una biblioteca en tus propios scripts. Los scripts a continuación se ejecutaron con Beancount 3.2.3, beanquery 0.2.0 y beangulp 0.2.0. El enfoque general es:
-
Carga tu libro mayor Beancount: Usa el cargador de Beancount para analizar el archivo
.beancounten objetos 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 desequilibrado o inválido aún devuelve entradas, por lo que verifica
errorsy detente antes de confiar en los datos. Todas tus cuentas, transacciones y saldos ahora son accesibles en código. -
Aprovecha Beancount Query Language (BQL): En lugar de iterar manualmente, puedes ejecutar consultas similares a SQL en los datos. Las consultas se encuentran en el paquete separado
beanquery. No existe un módulobeancount.queryen Beancount 3.2.3. Por ejemplo, para obtener el total de gastos 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 ejecutar un comando externo en un bucle. -
Configura una estructura de proyecto: Organiza tus scripts junto con tu libro mayor. Una distribución común es tener directorios para importadores (para obtener/parsear datos externos), informes o consultas (para scripts de análisis) y documentos (para almacenar estados de cuenta descargados). Por ejemplo, un usuario mantiene:
importers/– scripts personalizados de importación en Python (con pruebas),queries/– scripts para generar informes (ejecutables víapython3 queries/...),documents/– CSV/PDF bancarios descargados organizados por cuenta.
Con esta configuración, puedes ejecutar scripts manualmente (por ejemplo, python3 queries/cash_flow.py) o programarlos (mediante cron o un task runner) para automatizar tu flujo de trabajo.
Automatizando tareas de conciliación
Conciliación significa asegurarse de que tu libro mayor coincida con los registros externos (estados bancarios, reportes de tarjetas de crédito, etc.). El libro mayor en texto plano de Beancount y su API en Python 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 ingest v2 y su comando extract. Escribes una pequeña clase en Python que hereda de beangulp.Importer para parsear un formato dado (CSV, OFX, PDF, etc.) y producir transacciones. Regístralo en un script ingest corto, luego ejecútalo mediante bea ingest en el motor gestionado:
- Escribe un importador (una clase Python con los métodos
identify(),account()yextract()) para el formato CSV de tu banco. - Añade un script de ingesta que registre tus importadores.
bea ingestejecuta los comandosidentify,extractyarchivedel script. Por ejemplo, un flujo de trabajo ejecutaextracten todos los archivos en~/Downloadsy genera transacciones en un archivo temporal. - Revisa manualmente y copia las transacciones desde el archivo temporal a tu libro mayor principal, luego ejecuta
bea checkpara asegurar que los saldos cuadren.
Un ejemplo mínimo: un statement.csv con columnas date,description,amount, parseado 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 entriesEl script de ingesta (ingest.py) lo conecta:
from checking_importer import CheckingImporter
from beangulp import Ingest
ingest = Ingest([CheckingImporter()])
if __name__ == "__main__":
ingest()Ejecuta esto sobre un archivo descargado. No se requieren credenciales para un CSV local. Primero instala la librería libmagic del sistema. 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.beancountidentify 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 USDRevisa new.beancount, copia las entradas a tu libro mayor principal y ejecuta bea check.
No necesitas escribir un importador para convertir un solo extracto. Pega el archivo en el convertidor de CSV a Beancount, o usa OFX & QIF a Beancount para descargas .ofx, .qfx y .qif. Ambos corren completamente en tu navegador, por lo que el extracto nunca abandona tu equipo.
Aunque este proceso aún implica 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 afirmaciones 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 verifica que todas estas afirmaciones de saldo sean correctas, y marca cualquier error si faltan o están duplicadas transacciones. Esta es una buena práctica: generar automáticamente afirmaciones de saldo para cada período de extracto y permitir que la computadora detecte las diferencias sin conciliar por ti.
Scripts personalizados de conciliación (Intermedio)
Para mayor control, puedes escribir un script Python personalizado para comparar la lista de transacciones de un banco (CSV o vía API) con las entradas de tu libro mayor:
- Leer los datos externos: Analiza el archivo CSV del banco usando el módulo
csvde Python (o Pandas). Normaliza los datos en una lista de transacciones, por ejemplo, cada una con una fecha, monto y descripción. - Cargar transacciones del libro mayor: Usa
loader.load_filecomo se mostró anteriormente para obtener todas las entradas del libro mayor. Filtra esta lista para la cuenta de interés (por ejemplo, tu cuenta corriente) y quizás el rango de fechas del estado. - Comparar y encontrar discrepancias:
- Para cada transacción externa, verifica si existe una entrada idéntica en el libro mayor (coincidencia por fecha y monto, quizás descripción). Si no se encuentra, márcala como “nueva” y posiblemente imprímela como una transacción formateada para Beancount para que la revises.
- Por otro lado, identifica cualquier entrada en el libro mayor de esa cuenta que no aparezca en la fuente externa — estas podrían ser errores de ingreso de datos o transacciones que no han sido compensadas por el banco.
- Imprimir resultados: Imprime un reporte o crea un nuevo fragmento
.beancountcon las transacciones faltantes.
Como ejemplo, un script comunitario 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 en el libro mayor que no esté en la entrada (potencialmente una señal de mala clasificación). Con un script así, la conciliación mensual puede ser tan sencilla como ejecutarlo y luego agregar las transacciones sugeridas a tu libro mayor. Un usuario de Beancount señala que ellos “realizan un proceso de conciliación en todas las cuentas cada mes” y usan 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 afirmaciones de saldo como se mencionó, para tener chequeos automatizados sobre los saldos de cuenta.
- Usa la directiva
padsi lo deseas, que puede insertar automáticamente asientos de balance para diferencias menores de redondeo (úsalo con precaución). - Escribe pruebas unitarias para tu importador o lógica de conciliación (Beancount proporciona ayudas para pruebas). Por ejemplo, un flujo implicó tomar un CSV de muestra, escribir pruebas fallidas con las transacciones esperadas, luego implementar el importador hasta que todas las pruebas pasaron. Esto asegura que tu script de importación funciona correctamente para 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 variar desde simples salidas en consola hasta archivos o gráficos con formato enriquecido.
Consultar datos para informes (Principiante)
A un nivel básico, puedes usar el Beancount Query Language (BQL) para obtener datos resumidos y imprimirlos o guardarlos. Por ejemplo:
-
Resumen de flujo de caja: Usa una consulta para calcular el flujo neto de efectivo. “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, monthEsto netea todas las inscripciones de ingresos y gastos por mes. Filtra con
~y una expresión regular:LIKEes un error de sintaxis en beanquery 0.2.0. Las inscripciones llevanposition, noamount. Cada fila contiene un Inventory, por lo que cada moneda se lista por separado en lugar de ser convertida. Los ingresos aparecen negativos y los gastos positivos. Podrías ejecutar esto a través debea queryo mediante la API de Python de beanquery mostrada antes, y luego formatear el resultado. -
Reporte de gastos por categoría: Consulta el total de gastos por categoría:
SELECT account, sum(position) WHERE account ~ 'Expenses' GROUP BY account ORDER BY sum(position) ASCEsto genera una tabla de gastos por categoría. Cada total es un Inventory en su moneda original. No envuelvas el agregado en
round(): no existe la funciónround(inventory, int), por lo queround(sum(position), 2)no compila. Puedes ejecutar múltiples consultas en un script y exportar los resultados como texto, CSV o incluso JSON para un procesamiento posterior.
Un usuario encontró que era “trivial” analizar datos financieros con Fava o con scripts, mencionando que usa un script Python para extraer datos de Beancount mediante el Query Language y luego colocarlos en un Pandas DataFrame para preparar un reporte personalizado. Por ejemplo, podrías obtener totales mensuales con una consulta y luego usar Pandas/Matplotlib para graficar un 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 rendimiento de inversiones o crear salidas visuales:
-
Rendimiento de inversión (IRR/XIRR): Dado que tu libro mayor contiene todos los flujos de efectivo (compras, ventas, dividendos), puedes calcular las tasas de retorno de una 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. Hay bibliotecas (o fórmulas) para calcular IRR dado un flujo de caja. Algunas extensiones comunitarias de Fava (como PortfolioSummary o fava_investor) hacen exactamente esto, calculando IRR y otras métricas para carteras de inversión. Como script, podrías usar una función IRR (de NumPy o propia) sobre la serie de contribuciones/retiros más el valor final.
-
Métricas multiperíodo o personalizadas: ¿Quieres un informe de tu tasa de ahorro (proporción de ahorros respecto al ingreso) cada mes? Un script en Python puede cargar el libro mayor, sumar todas las cuentas de Ingresos y todas las cuentas de Gastos, luego calcular ahorro = ingresos - gastos y el porcentaje. Esto podría generar una tabla agradable o incluso un informe en HTML/Markdown para tus registros.
-
Visualización: Puedes generar gráficos fuera de Fava. Por ejemplo, usa
matplotliboaltairen un script para crear un gráfico de patrimonio neto a lo largo del tiempo, usando datos del libro mayor. Como el libro mayor tiene todos los saldos históricos (o puedes acumularlos iterando sobre las entradas), puedes producir gráficos de series temporales. Guarda estos gráficos como imágenes o HTML interactivo. (Si prefieres visualizaciones dentro de la aplicación, consulta la sección de extensión de Fava abajo para añadir gráficos dentro de Fava.)
Opciones de salida: Decide cómo entregar el informe:
- Para análisis puntuales, imprimir en pantalla o guardar en un archivo CSV/Excel podría ser suficiente.
- Para tableros, considera generar un archivo HTML con los datos (posiblemente usando una librería de plantillas como Jinja2 o incluso escribiendo Markdown) que puedas abrir en un navegador.
- También puedes integrar con Jupyter Notebooks para un entorno de reporte interactivo, aunque esto es más para exploración que para automatización.
Activación de alertas desde tu libro mayor
Otro uso poderoso de flujos de trabajo scriptables es configurar alertas basadas en condiciones en tus datos financieros. Como tu libro mayor se actualiza regularmente (y puede incluir ítems 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, podrías querer una alerta si alguna cuenta (por ejemplo, corriente o de ahorros) cae por debajo de un umbral. Aquí te explicamos cómo implementarlo:
-
Determinar saldos actuales: Después de cargar
entriesmediante el cargador, calcula el saldo más reciente de las cuentas de interés. Puedes hacerlo agregando partidas 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 todas sus partidas). 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 commoditiesPase solamente las entradas: el segundo parámetro es
min_accounts, no el mapa de opciones. Luego extraiga el valor numérico (por ejemplo,balance.get_currency_units('USD')devuelve el monto Decimal en USD). Como una agregación de consulta, el saldo mantiene cada moneda por separado. Sin embargo, usar la consulta es más simple para la mayoría de los casos. -
Verificar el umbral: Compare el saldo con su límite predefinido. Si está por debajo, active una alerta.
-
Activar notificación: Esto podría ser tan simple como imprimir una advertencia en consola, pero para alertas reales podría enviar un correo electrónico o una notificación push. Puede integrarse con correo electrónico (a través de
smtplib) o un servicio como IFTTT o la API webhook de Slack para enviar la alerta. Por ejemplo:if balance < 1000: send_email("Low balance alert", f"Account XYZ balance is {balance}")(Implemente
send_emailcon los detalles de su servidor de correo.)
Ejecutando este script diariamente (mediante un trabajo cron o el Programador de tareas de Windows), recibirá advertencias proactivas. Debido a que usa el libro mayor, puede considerar todas las transacciones, incluidas las que acaba de agregar.
Vencimientos de Pagos Próximos
Si usa Beancount para registrar facturas o vencimientos, puede marcar pagos futuros y hacer que los scripts le recuerden. Dos formas de representar obligaciones próximas en Beancount:
-
Eventos: Beancount soporta una directiva
eventpara notas fechadas arbitrarias. 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
entriespara entradasEventdondeEvent.type == "BillDue"(o cualquier tipo personalizado que elija) y verificar si la fecha está dentro, digamos, de los próximos 7 días a partir de hoy. Si es así, active una alerta (correo electrónico, notificación o incluso una ventana emergente). -
Transacciones Futuras: Algunas personas ingresan 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 ejecute informes con fecha futura). Un script puede buscar transacciones fechadas en un futuro cercano y listarlas.
Usando esto, podría crear un script “recordatorio” que, al ejecutarse, genere una lista de tareas o facturas próximas a vencer. Puede integrarse con una API como Google Calendar o un gestor de tareas si desea crear recordatorios automáticamente allí.
Detección de Anomalías
Más allá de los umbrales o fechas conocidas, puedes programar alertas personalizadas para patrones inusuales. Por ejemplo, si un gasto que suele ser mensual no ha ocurrido (quizá olvidaste pagar una factura), o si el gasto en una categoría es anormalmente alto este mes, tu script podría marcarlo. Esto generalmente implica consultar datos recientes y compararlos con el historial (lo cual podría ser un tema avanzado – posiblemente usando 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 electrónicos por cada transacción), podrías analizar esos correos con un script y añadirlos automáticamente a Beancount, o al menos verificar que estén registrados. Un entusiasta incluso configuró su banco para enviar correos de alerta de transacciones, con el plan de analizarlos y agregarlos automáticamente al libro mayor. 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 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 Python que define una clase que hereda de fava.ext.FavaExtensionBase. La registras en tu archivo de Beancount mediante una opción personalizada. Por ejemplo, si tienes un archivo myextension.py con una clase MyAlerts(FavaExtensionBase), puedes habilitarla añadiendo al libro mayor:
1970-01-01 custom "fava-extension" "myextension"Cuando Fava se cargue, importará ese módulo e inicializará tu clase MyAlerts.
Las extensiones pueden hacer varias cosas:
- Hooks: Pueden engancharse a eventos en el ciclo de vida de Fava. Por ejemplo,
after_load_file()se llama después de que se carga el libro mayor. Podrías usar esto para ejecutar verificaciones o precomputar datos. Si quisieras implementar la verificación de saldo bajo dentro de Fava,after_load_filepodría iterar sobre los saldos de cuentas y quizás almacenar advertencias (aunque mostrarlas en la interfaz de usuario podría requerir un poco 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 establece un atributo
report_title, Fava añadirá una nueva página en la barra lateral para ello. Luego proporcionas una plantilla (HTML/Jinja2) para el contenido de esa página. Así es como creas vistas completamente nuevas, como un panel o resumen que Fava no tiene por defecto. La extensión puede recopilar los datos que necesite (puedes acceder aself.ledgerque contiene 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 listando tus posiciones de cartera. Las extensiones de la comunidad van más lejos:
- Paneles de control (Dashboards): El plugin fava-dashboards permite definir gráficos y paneles personalizados (usando librerías como Apache ECharts). Lee una configuración YAML con consultas a ejecutar, las ejecuta mediante Beancount y genera una página de panel dinámico en Fava. En esencia, conecta los datos de Beancount con una librería JavaScript de gráficos para producir visualizaciones interactivas.
- Análisis de cartera: La extensión PortfolioSummary (contribución de usuarios) calcula resúmenes de inversión (agrupando cuentas, calculando TIR, 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 (por ejemplo, para asegurarte de que no perdiste ningún recibo).
Para crear una extensión simple tú mismo, comienza por subclasear 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 colocaste esto en hello.py y añadiste custom "fava-extension" "hello" a tu libro mayor, Fava mostraría una nueva página "Hello World" (también necesitarías un archivo plantilla HelloReport.html en una subcarpeta templates para definir el contenido de la página, a menos que la extensión use solo hooks). La plantilla puede usar datos que adjuntes a la clase de extensión. Fava usa plantillas Jinja2, por lo 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 desarrollo web (HTML/JS) si estás creando 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 las extensiones de Fava cuando quieras una experiencia personalizada 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 scriptables es la capacidad de incorporar datos externos. Aquí están las integraciones comunes:
-
Tipos de cambio y commodities: Beancount no obtiene precios automáticamente por diseño (para mantener los informes deterministas), pero proporciona una directiva Price para que suministres las tasas. Puedes automatizar la obtención de estos precios. Por ejemplo, un script puede consultar una API (Yahoo Finance, Alpha Vantage, etc.) para obtener el último tipo de cambio o precio de acción y añadir una entrada de precio a tu libro mayor:
2025-04-30 price BTC 30000 USD 2025-04-30 price EUR 1.10 USDHay herramientas como
bea price, respaldadas por Beanprice en el motor gestionado que obtienen cotizaciones diarias y las generan en formato Beancount. Podrías habilitarlo una vez conbea engine enable beanprice, luego programarbea price main.beancountpara que se ejecute cada noche para actualizar un archivo de inclusiónprices.beancount. O usar Python: por ejemplo, con la bibliotecarequestspara llamar a una API. La documentación de Beancount sugiere que para activos cotizados públicamente, puedes “invocar algún código que descargue precios y genere las directivas por ti.” En otras palabras, deja que un script haga la consulta e inserte las líneasprice, en lugar de hacerlo manualmente. -
Datos de cartera de acciones: Similar a los tipos de cambio, puedes integrarte con APIs para obtener datos detallados de acciones o dividendos. Por ejemplo, la API de Yahoo Finance (o bibliotecas comunitarias como
yfinance) puede recuperar datos históricos para un símbolo bursátil. Un script podría actualizar tu libro mayor con el historial mensual de precios para cada acción que poseas, permitiendo informes históricos precisos del valor de mercado. Algunas extensiones personalizadas (como fava_investor) incluso obtienen datos de precios al vuelo para mostrar, pero lo más simple es importar regularmente los precios al libro mayor. -
APIs bancarias (Open Banking/Plaid): En lugar de descargar CSV, puedes usar APIs para obtener transacciones automáticamente. Servicios como Plaid agregan cuentas bancarias y permiten el acceso programático a transacciones. En una configuración avanzada, podrías tener un script en Python que use la API de Plaid para extraer nuevas transacciones diariamente y guardarlas en un archivo (o importarlas directamente al libro mayor). Un usuario avanzado construyó un sistema donde Plaid alimenta su canal de importación, haciendo que sus libros sean 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 la lógica de importación de Beancount para convertirlos en entradas del libro mayor. Algunas regiones tienen APIs de banca abierta proporcionadas por bancos; esas podrían usarse de manera similar.
-
Otras APIs: Podrías integrar herramientas de presupuestos (exportando presupuestos planeados para comparar con los reales en Beancount), o usar una API OCR para leer recibos y emparejarlos automáticamente con transacciones. Como tus scripts tienen acceso completo al ecosistema de Python, puedes integrar desde servicios de correo electrónico (para enviar alertas) hasta Google Sheets (por ejemplo, actualizar una hoja con métricas financieras mensuales), y aplicaciones de mensajería (enviarte un informe resumen vía un bot de Telegram).
Al usar APIs de terceros, recuerda proteger tus credenciales (usa variables de entorno o archivos de configuración para las llaves API), y maneja errores (problemas de red, caídas de API) con elegancia en tus scripts. A menudo es recomendable almacenar en caché los datos (por ejemplo, guardar tasas de cambio obtenidas para no pedir repetidamente la misma tasa histórica).
Mejores prácticas para scripts modulares y mantenibles
Mientras construyes flujos de trabajo con scripts, mantén tu código organizado y robusto:
-
Modularidad: Divide diferentes responsabilidades en distintos scripts o módulos. Por ejemplo, ten scripts separados para “importación/reconciliación de datos”, “generación de informes” y “alertas”. Incluso puedes crear un pequeño paquete en Python para tu libro mayor 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 API, rangos de fechas, etc. Esto facilita ajustar sin editar el código profundamente. Por ejemplo, define
LOW_BALANCE_THRESHOLDS = {"Assets:Bank:Checking": 500, "Assets:Savings": 1000}al inicio, y tu script de alertas puede recorrer este diccionario. -
Pruebas: Trata tu automatización financiera como código crítico para la misión, ¡porque lo es! Escribe pruebas para lógica compleja. Beancount proporciona algunos ayudantes para pruebas (usados internamente para probar importadores) que puedes aprovechar para simular entradas al libro mayor. Incluso sin frameworks sofisticados, puedes tener un CSV ficticio y las transacciones esperadas como salida, y afirmar que tu script de importación produce las entradas correctas. Si usas
pytest, puedes integrar estas pruebas fácilmente (como Alex Watt hizo mediante un comandojust testque envuelve pytest). -
Control de versiones: Mantén tu libro mayor y scripts bajo control de versiones (git). Esto no solo te brinda copias de seguridad e historial, sino que te anima a hacer cambios de manera controlada. Puedes etiquetar versiones de tus “scripts financieros” o revisar diferencias al depurar un problema. Algunos usuarios incluso llevan el seguimiento de sus registros financieros en Git para ver cambios a través del tiempo. Solo ten cuidado de ignorar datos sensibles (como archivos de estados bancarios sin procesar o claves 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. Además, comenta tu código, especialmente cualquier lógica contable no obvia o interacción con APIs.
-
Mantenimiento de Plugins de Fava: Si escribes una extensión para Fava, mantenla simple. Fava puede cambiar, así que extensiones más pequeñas con funcionalidades específicas 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 cambios en el libro mayor.
-
Seguridad: Dado que tus scripts pueden manejar datos sensibles y conectarse a servicios externos, trátalos con cuidado. No expongas claves API, y considera ejecutar tu automatización en una máquina segura. Si usas una solución alojada o en la nube (como programar GitHub Actions o un servidor para correr Fava), asegúrate de que los datos de tu libro mayor estén cifrados en reposo y que estés conforme con las implicaciones de privacidad.
Al seguir estas prácticas, aseguras que tu flujo de trabajo se mantenga confiable incluso cuando tus finanzas (y las herramientas mismas) evolucionen. Quieres scripts que puedas reutilizar año tras año, con ajustes mínimos.
Conclusión
Beancount y Fava ofrecen una plataforma potente y flexible para usuarios técnicos que desean personalizar completamente el seguimiento de sus finanzas personales. Escribiendo scripts en Python, puedes automatizar tareas tediosas como conciliar estados de cuenta, producir informes detallados adaptados a tus necesidades, y mantener el control de tus finanzas con alertas oportunas. Cubrimos una variedad de ejemplos desde básicos hasta avanzados, comenzando con consultas simples e importaciones CSV, y avanzando hacia plugins completos de Fava e integraciones externas de API. Al implementarlos, comienza simple y ve incrementando gradualmente. Incluso unos pocos scripts de automatización pequeños pueden ahorrar horas de trabajo y mejorar enormemente la precisión. Y recuerda, porque todo es texto plano y Python, tienes control total: tu sistema financiero crece contigo, adaptándose a tus necesidades específicas. ¡Feliz scripting!
Fuentes: Las técnicas mencionadas anteriormente provienen de la documentación de Beancount y la experiencia de la comunidad. Para más información, consulta la documentación oficial de Beancount, guías comunitarias y blogs, y el repositorio Awesome Beancount para enlaces a plugins y herramientas útiles.