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/FishCat233/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. Can be specified multiple times to load from several files. 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
# Multiple rules files
beancount-helper ccb.xls -p ccb -r food.txt -r transport.txt -r income.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. The syntax is:
p=field:method:value
Available fields
| Field | Description | CCB | |
|---|---|---|---|
opposite |
Counterparty name (parsed) | ✓ | ✓ |
raw_opposite |
Raw counterparty as in the statement | ✓ | — |
note |
Remarks / memo | ✓ | ✓ |
product |
Product description | — | ✓ |
Methods
| Method | Meaning | Example |
|---|---|---|
eq |
Field equals the value exactly | p=opposite:eq:Starbucks |
in |
Field contains the substring | p=note:in:refund |
re |
Field matches the regex pattern | p=opposite:re:^ATM\d+$ |
Examples
# Match an exact merchant name
p=opposite:eq:China Mobile=>Expenses:Utilities:Phone
# Match anything with "restaurant" in the note
p=note:in:restaurant=>Expenses:Food:Dining
# Match product descriptions starting with "JD-"
p=product:re:^JD-=>Expenses:Shopping:Online
# Combine with other conditions
p=opposite:eq:DiDi;;direct=out=>Expenses:Transport:Ride
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/
├── src/beancount_helper/
│ ├── cli.py CLI entry point
│ ├── beancount/core.py BeanCount model + serialization
│ ├── bill_resolver/
│ │ ├── ccb.py CCB Excel parser
│ │ └── wechat.py WeChat Excel parser
│ └── transformer/rule.py Rule matching engine
├── rules.example.txt Sample rule set
└── test/
├── test_beancount_core.py
└── test_rule_matcher.py
Development
# Clone & editable install
git clone https://github.com/FishCat233/beancount-helper.git
cd beancount-helper
uv sync
# Run tests
uv run pytest
# Lint
uv run ruff check .
License
MIT
Metadata
Release files for beancount-helper 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| beancount_helper-0.2.1.tar.gz | 36.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| beancount_helper-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.9 kB
Release files / beancount_helper-0.2.1.tar.gz
| Download URL | beancount_helper-0.2.1.tar.gz |
|---|---|
| Size | 36.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f05b58e1c8c8cc340020840433d2c2e8a62b7c990f16b82d235e9f0017508ca7
|
|
BLAKE2b-256 checksum How to use checksums |
e955d10ba08c4df29e47f6221bad1e996afec49d5e89ddcc6eeb5eb2ace5ca81
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / beancount_helper-0.2.1-py3-none-any.whl
| Download URL | beancount_helper-0.2.1-py3-none-any.whl |
|---|---|
| Size | 12.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c61e5ef62b5d0c8b67761dda990516da41f9335488222bd92d0954f68d31cc65
|
|
BLAKE2b-256 checksum How to use checksums |
5bd514a98d6cb315f4540df5bf6a397cfc8c216106f96a170414dffecf54adc0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for beancount-helper 0.2.1
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.