Balances CSV format

Balance-tracked accounts — a savings account, a pension, a mortgage, a rental valuation — are worth whatever you say they're worth on a given day. Entering those one at a time is fine for one account. It is not fine for five accounts and three years of month-end statements, which is what this format is for.

Three columns: which account, which day, how much. Everything else about the file behaves exactly like the trades CSV — same comma-delimited RFC 4180 quoting, same encoding detection on upload (UTF-8, UTF-16, or cp1252, with or without a byte-order mark), same preview before anything is written. Export and re-import round-trip losslessly.

The header row

The first line must be exactly this, all three columns, in this order:

name,date,amount

Nothing else is accepted — not a subset, not a reordering, not your bank's own header. Import in the header opens the dialog; pick Balances in the format tabs, or just drop the file on the Trades tab and let the header row switch it for you. Download template gives you the header plus two example rows.

Columns

Column Required What it holds
name yes Account name, matched case-insensitively against your non-archived, balance-tracked accounts. An unmatched name is a row error — import never creates accounts.
date yes YYYY-MM-DD.
amount yes The account's whole value at the end of that day. Plain decimal — no thousands separators, no currency symbols. Negative for a liability (a mortgage, a card balance), written exactly as you mean it: we never flip the sign for you.

Formats

These are strict, because a silently misread number is worse than a rejected row — and they're the same rules the trades file uses.

  • Dates are YYYY-MM-DD, zero-padded, hyphens only, and must be real calendar dates. 2024-02-30 is rejected.
  • Amounts are plain decimals: an optional leading -, digits, an optional . and more digits. No $, no 1,234.00, no (1234) for a negative, no scientific notation. Quote a value only if it contains a comma — in which case it isn't a plain decimal anyway, and will be rejected.
  • Whitespace around any of the three values is trimmed.
  • A blank amount is a row error. There is nothing to compute it from: the number is the row.

Balance accounts only

A row naming a holdings-tracked account is a row error, not a silent success. A holdings account's value comes from its trades and its cash, and the app never reads balance snapshots for one — so storing a snapshot there would look like it worked and then change nothing. See Tracking level if you're not sure which kind an account is.

The account list shown above the drop zone follows this: on the Balances tab, it lists only the accounts a row could actually land in.

Repeating a date replaces it

A snapshot is filed under its date, so re-stating a date is an edit, not a duplicate. This is the same rule as typing over a row in Balance history, and it works in both directions:

  • Against what's already stored — the row overwrites the balance on that date. The preview counts these before you commit: 3 rows replace balances already stored on those dates. This is the one thing in this format that re-importing can't undo, which is why it's called out before the confirm and again in the result.
  • Within one file — if two rows name the same account and the same date, the last one wins, and the earlier one is reported as a duplicate that wasn't written.

Different accounts on the same date are not duplicates, and neither are different dates on the same account. Both are the ordinary case: one row per account per statement date.

The preview

Identical to the trades import. Every file runs as a dry run first:

38 rows · 36 valid · 1 duplicates · 1 errors

Then one line per row, with its line number and one of three statuses — Valid (will be written), Duplicate (superseded by a later row for the same account and date), or Error (with the reason next to it). Long files show the first 200 rows.

Press Import n balances to commit. Afterwards you get four counts — Imported, Replaced an existing balance, Skipped as duplicate, and Failed — with the failures listed by line.

A bad row never stops the rest of the file.

Exporting

Export CSV in the import dialog exports whichever format the tabs are on, so switch to Balances first. The export covers exactly what the import accepts — every non-archived, balance-tracked account — so an exported file always re-imports. Rows come out sorted by account name, then date, which is the order you'd want to read a balance history in. Viewers can export too.

A stray snapshot on a holdings account (they can be written through the API) is deliberately left out of the export: a file that failed against its own format would be worse than a missing row.

Worked example

name,date,amount
Everyday Checking,2024-01-31,4820.11
Everyday Checking,2024-02-29,5210.4
Everyday Checking,2024-03-31,4990
"Ally Savings, ""joint""",2024-01-31,25000
Mortgage,2024-01-31,-312450.88

Three month-end snapshots for one account, an account whose name contains a comma and a quote (so it's wrapped, with the inner quotes doubled — plain RFC 4180), and a mortgage carrying a negative balance.

Who can do this

Importing balances requires editor or owner access, like every other write. Viewers can export.