Skip to main content

beancount-helper

Convert bank statement Excel files into Beancount transactions with a rule-based account matching engine.

2025-01-15 * "Coffee Shop" "Latte"
  Expenses:Food:Coffee  25.00 CNY
  Assets:CCB

Supported banks

Parser Source
ccb China Construction Bank (建设银行) statement .xls
wechat WeChat Pay (微信支付) statement .xlsx

Installation

pip install beancount-helper

For development:

git clone https://github.com/your-org/beancount-helper.git
cd beancount-helper
uv sync

Quick start

Step 1 — Export your statement from the bank app and save it locally.

Step 2 — (Optional) Create a rules file:

# rules.txt
p=opposite:eq:Coffee Shop;;direct=out=>Expenses:Food:Coffee
direct=in=>Income:Misc

Step 3 — Run:

beancount-helper ccb.xls -p ccb -r rules.txt -o ledger.beancount

That's it. Every record falls into a Beancount account — either matched by your rules, or placed in Equity:Opening-Balances as a fallback.

CLI reference

beancount-helper INPUT -p PARSER [-r RULES] [-o OUTPUT] [--asset ASSET] [--default-account ACCOUNT]
Argument Required Default Description
INPUT yes — Path to the bank statement file (.xls / .xlsx).
-p, --parser yes — ccb or wechat.
-r, --rules no — Path to a rules file. Without it, all records use the default account.
-o, --output no output.beancount Output file path.
--asset no Assets:CCB / Assets:WeChat Asset account for the source of funds.
--default-account no Equity:Opening-Balances Fallback account when no rule matches.

Examples

# Bare minimum — everything goes to Equity:Opening-Balances
beancount-helper ccb.xls -p ccb

# With rules
beancount-helper wechat.xlsx -p wechat -r rules.txt

# Custom accounts
beancount-helper ccb.xls -p ccb -r rules.txt \
  --asset Assets:CCB:Savings \
  --default-account Expenses:Pending

Rule system

Rules tell the tool which Beancount account a bill should be posted to. Each rule has this shape:

condition1;;condition2;;...=>TargetAccount

Conditions are AND-ed: a bill must satisfy all of them for the rule to fire. Rules are tried in order; the first match wins.

Condition reference

Direction (direct / direction)

Matches whether money flows in or out.

direct=in       # income
direct=out      # expense

Property (p / property)

Matches a field on the bill record.

Method Syntax Example
exact p=field:eq:value p=opposite:eq:Coffee Shop
contains p=field:in:substring p=note:in:lunch
regex p=field:re:pattern p=product:re:^ATMS$

Available fields: opposite, note, product (wechat only).

Amount comparisons

Operator Meaning
lt=N amount < N
le=N amount ≤ N
gt=N amount > N
ge=N amount ≥ N
eq=N amount = N

Negative amounts are expenses, positive are income (from the bank's perspective).

Combining conditions

Separate conditions with ;;:

# Small lunch expenses from a specific vendor
direct=out;;p=opposite:in:Restaurant;;lt=50.0=>Expenses:Food:Lunch

# Any income
direct=in=>Income:Misc

Rule file format

One rule per line. Blank lines and #-comments are ignored.

# Food & drinks
p=opposite:eq:Starbucks=>Expenses:Food:Coffee
p=opposite:in:Pizza;;lt=80.0=>Expenses:Food:Takeout

# Transport
p=opposite:eq:DiDi=>Expenses:Transport:Ride
p=note:re:metro|subway=>Expenses:Transport:Transit

# Income
direct=in;;gt=5000.0=>Income:Salary
direct=in=>Income:Misc

How it works

Bank Excel (.xls/.xlsx)
        │
        ▼
  bill_resolver       ← parses bank-specific formats into Bill objects
        │
        ▼
  transformer.rule    ← matches each Bill against the rule set
        │
        ▼
  beancount.core      ← assembles BeanCount transactions, dumps to text
        │
        ▼
  output.beancount

Project structure

beancount-helper/
├── main.py                    CLI entry point
├── rules.example.txt          Sample rule set
├── src/
│   ├── beancount/core.py      BeanCount model + serialization
│   ├── bill_resolver/
│   │   ├── ccb.py             CCB Excel parser
│   │   └── wechat.py          WeChat Excel parser
│   └── transformer/rule.py    Rule matching engine
└── test/
    ├── test_beancount_core.py
    └── rule_matcher.py

Development

# Install dev dependencies
uv sync

# Run tests
uv run pytest

# Lint
uv run ruff check .

License

MIT

Metadata

Release files for beancount-helper 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for beancount-helper 0.1.0
File Size Uploaded Provenance
beancount_helper-0.1.0.tar.gz 32.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for beancount-helper 0.1.0
File Interpreter ABI Platform
beancount_helper-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 43.7 kB

Release files / beancount_helper-0.1.0.tar.gz

Download URL beancount_helper-0.1.0.tar.gz
Size 32.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d9280a1047943db1e48bc2d425bde84055a1a6b1928936618a2f672fe0848003
BLAKE2b-256 checksum
How to use checksums
b3a53973b477aba6d521eb65e51cfa62a90aadd513355636c257fd3a928aec27
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / beancount_helper-0.1.0-py3-none-any.whl

Download URL beancount_helper-0.1.0-py3-none-any.whl
Size 11.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
33d7a4abe03c7164ded85ecd8e40214decfb7b08f74c6ded86586274e8c892f0
BLAKE2b-256 checksum
How to use checksums
77e36e91feaf8069f42442d375d08ed3fbd57efeaa908c6c03e356a2172a9999
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Security for beancount-helper 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page