Case study · Personal project · Runs locallyCaso de estudio · Proyecto personal · Corre en local

Personal finance pipelinePipeline de finanzas personales

Bank and card statements arrive as PDFs, each in its own layout. I built a local pipeline that reads them, cleans every transaction into one database and answers a practical question: what is due before the next paycheck?

Los estados de cuenta de bancos y tarjetas llegan en PDF, cada uno con su propio formato. Construí un pipeline local que los lee, limpia cada transacción en una sola base de datos y responde una pregunta práctica: ¿qué vence antes del próximo ingreso?

In use since 2026En uso desde 2026
9
accounts and cards in one ledgercuentas y tarjetas en un solo registro
4 + OCR
statement parsers, plus OCR for scanned filesparsers de estados de cuenta, más OCR para escaneados
15
tables in the SQLite data modeltablas en el modelo de datos en SQLite
29 + 4
duplicated and miscategorized transactions found in an audittransacciones duplicadas y mal categorizadas encontradas en una auditoría

The problemEl problema

The numbers existed, but spread across formats and mixed in ways that made every total wrong.Los números existían, pero repartidos en formatos distintos y mezclados de formas que hacían que cada total saliera mal.

A different PDF per bankUn PDF distinto por banco

Each issuer lays out dates, amounts and installments differently, and some statements only exist as scanned images.

Cada emisor acomoda fechas, montos y mensualidades a su manera, y algunos estados solo existen como imagen escaneada.

Not everything is spendingNo todo es gasto

Card payments, installment plans, interest and transfers between my own accounts all look like charges if you just add them up.

Pagos de tarjeta, compras a meses, intereses y transferencias entre mis propias cuentas parecen cargos si solo se suman.

No view of what is dueSin ver qué vence

Balances were easy to find. What actually had to be paid, and when, compared with the next income date, was not.

Los saldos eran fáciles de encontrar. Lo que de verdad había que pagar, y cuándo, frente a la fecha del próximo ingreso, no.

What I builtLo que construí

A pipeline that runs on my own machine. No bank credentials and no third-party services: statements go in, a clean ledger comes out.Un pipeline que corre en mi propia computadora. Sin credenciales bancarias ni servicios de terceros: entran estados de cuenta y sale un registro limpio.

  1. PDF statement
  2. Text or OCR
  3. Parser per bank
  4. Normalized rows
  5. Rules and classification
  6. Ledger and findings
  1. Estado en PDF
  2. Texto u OCR
  3. Parser por banco
  4. Filas normalizadas
  5. Reglas y clasificación
  6. Registro y hallazgos

Every statement goes through the same steps.Cada estado de cuenta pasa por los mismos pasos.

Parsers and OCRParsers y OCR

One parser per issuer reads dates, merchants, amounts, installments and statement totals.

Un parser por emisor lee fechas, comercios, montos, mensualidades y totales del corte.

  • PDF text extraction with pdfplumber; Tesseract OCR for scanned statements
  • Each statement stored with its cut date, due date, minimum payment and balance
  • Extracción de texto con pdfplumber; OCR con Tesseract para estados escaneados
  • Cada estado se guarda con su fecha de corte, fecha límite, pago mínimo y saldo

ClassificationClasificación

Two separate labels per transaction: what kind of movement it is, and what it was spent on.

Dos etiquetas separadas por transacción: qué tipo de movimiento es y en qué se gastó.

  • Movement type: spending, payment, installment plan, interest and fees
  • 9 spending categories matched by 48 merchant keywords, plus rules learned from manual corrections
  • Tipo de movimiento: gasto, pago, compra a meses, intereses y comisiones
  • 9 categorías de gasto detectadas por 48 palabras clave de comercio, más reglas aprendidas de correcciones manuales

Cash-flow ledgerRegistro de flujo de caja

A cash ledger kept apart from consumption, with direction and ownership on every entry.

Un registro de efectivo separado del consumo, con dirección y propietario en cada movimiento.

  • Transfers between my own accounts are neutral, so they never count as income or spending
  • Payments made by someone else are tracked without becoming my income
  • Las transferencias entre mis propias cuentas son neutras: nunca cuentan como ingreso ni como gasto
  • Los pagos que hace otra persona se registran sin convertirse en mi ingreso

Statements and findingsCortes y hallazgos

Each statement has a status, and a findings engine points at what needs attention.

Cada corte tiene un estado, y un motor de hallazgos señala lo que necesita atención.

  • Statuses: to confirm, pending, paid, deferred, partial; only pending ones enter the cash calendar
  • Flags categories above their average, charges left in “Other” and repeated merchants
  • Estados: por confirmar, pendiente, pagado, diferido, pago parcial; solo los pendientes entran al calendario de caja
  • Señala categorías por encima de su promedio, cargos que quedaron en “Otros” y comercios repetidos

The appLa app

The real app and its logic, running on a copy loaded with fictional data. No real account, amount or transaction appears here.La app y su lógica reales, corriendo en una copia cargada con datos ficticios. Aquí no aparece ninguna cuenta, monto ni transacción real.

Mi Dinero · InicioSample dataDatos ficticios
Monthly overview: what is due before the next income and the real cash flow
Monthly overview: what is due before the next income, statements waiting for confirmation, and the real cash flow with transfers between own accounts kept neutral.Panorama del mes: qué vence antes del próximo ingreso, cortes por confirmar y el flujo real de efectivo, con las transferencias entre cuentas propias como neutras.
Mi Dinero · InicioSample dataDatos ficticios
Month composition split into new spending, interest and installments, with categories and trend
New spending, interest and installment plans counted separately, so a purchase is never confused with its monthly payments.Gasto nuevo, intereses y compras a meses por separado, para no confundir una compra con sus mensualidades.
Mi Dinero · InicioSample dataDatos ficticios
Findings: categories above average, charges to review, repeated merchants
Findings: categories above their average, charges left in “Other” and repeated merchants.Hallazgos: categorías por encima de su promedio, cargos en “Otros” y comercios repetidos.
Mi Dinero · DeudasSample dataDatos ficticios
Cards with the status of each statement
Each card’s latest statement with its own status: pending, paid, deferred or to confirm.El último corte de cada tarjeta con su propio estado: pendiente, pagado, diferido o por confirmar.
Mi Dinero · MovimientosSample dataDatos ficticios
Transactions with category and movement type, editable
Every transaction with two labels, category and movement type. A manual correction can be remembered as a rule for that merchant.Cada transacción con dos etiquetas, categoría y tipo de movimiento. Una corrección manual se puede guardar como regla para ese comercio.

Before and afterAntes y después

How raw statement lines become clean rows. The classification rules are the real ones; the rows are sample data.Cómo las líneas crudas de un estado de cuenta se vuelven filas limpias. Las reglas de clasificación son las reales; las filas son datos de ejemplo.

Raw line in the statementLínea cruda del estado DateFecha MerchantComercio AmountMonto MovementMovimiento CategoryCategoría
14-SEP-2026 DLC*UBER EATS CIUDAD DE MEX $286.402026-09-14Uber Eats$286.40SpendingGastoFoodComida
15 SEP TRASPASO A MSI 03/12 TIENDA DEPTAL $1,250.002026-09-15Department storeTienda departamental$1,250.00Installment planCompra a mesesFinancingFinanciamiento
15 SEP IVA INTERES COMPRA EN CUOTAS $38.722026-09-15—$38.72Interest and feesIntereses y comisionesInterest and feesIntereses y comisiones
18 SEP SU PAGO GRACIAS $4,000.002026-09-18—−$4,000.00PaymentPago—
SPEI ENVIADO A CUENTA PROPIA $2,000.002026-09-16—$2,000.00Own transfer (neutral)Transferencia propia (neutra)—

Without these rules, the last four rows would all be added up as new spending.Sin estas reglas, las últimas cuatro filas se sumarían como gasto nuevo.

ResultsResultados

I use it every month to see what is due before the next income and how much is really left over.

A data-quality audit found 29 duplicated transactions and 4 in the wrong category. Together they inflated one month’s spending by about 25%, and fixing them changed what the month actually looked like.

Lo uso cada mes para ver qué vence antes del próximo ingreso y cuánto sobra de verdad.

Una auditoría de calidad de datos encontró 29 transacciones duplicadas y 4 en la categoría equivocada. Juntas inflaban el gasto de un mes en cerca de 25%, y corregirlas cambió cómo se veía ese mes en realidad.

RoleRol
Design, development and monthly useDiseño, desarrollo y uso mensual
Stack
Python, SQLite, pdfplumber, Tesseract OCR, HTML/JS
PrivacyPrivacidad
Runs locally; no bank credentials. Screens and tables on this page use fictional dataCorre en local; sin credenciales bancarias. Las pantallas y tablas de esta página usan datos ficticios