Money, exactly
Amounts are stored as whole numbers of the smallest unit: cents for the dollar or the euro, thousandths for the three-decimal dinars and rials, whole yen for the yen. Nothing is ever a floating-point number, so 0.10 plus 0.20 is always exactly 0.30. Exchange rates are kept as written ("0.9215") and applied with whole-number arithmetic, rounding only once at the end, half away from zero.
Every transaction keeps its amount in its account's currency and, beside it, the value in your main currency at the time. Reports add up the second one, so a purchase in euros from last spring is not revalued by today's rate.
Your money month
A month starts on your payday (any day from the 1st to the 28th) and ends the day before the next one. With a payday on the 25th, each month runs from the 25th to the 24th of the following month. Budgets, the salary and the charts all follow it.
Safe to spend today
When you pay yourself a salary, the month has that much to spend. Money that lands in your spending account during the month (a refund, a gift) adds to it.
"Bills still to come" are the recurring costs on your spending accounts that are due before the month ends and have not been recorded yet. Keeping them aside is what makes the number safe.
Pace
Pace compares everyday spending with an even spread across the month. Fixed bills are left out on both sides, because a gym membership on the 3rd is not overspending. "At this pace" projects your average everyday spend over the days left, and says when the month would run out.
Runway
The runway is a projection of your savings accounts. Starting from today's balance, it takes your salary on every payday, adds recurring income paid into savings (contract work that starts later, a pension) and subtracts recurring costs paid from savings (a yearly insurance). The chart draws it as a staircase, because that is what your balance really does.
- Salaries left counts the paydays that can be paid in full without going below your floor.
- The floor is a cushion you choose; the plan treats it as untouchable.
- The target check works out your savings on the date you care about. If they fall short, it says by how much and how many paydays early the money runs out.
Without a salary, Ballast uses your average month instead: the money that went out minus the money that came in, over the last three full months, projected forward one month at a time.
Budgets
A budget is a monthly amount for one category. The bar fills as you spend, and a thin line marks where an even pace would be today. A budget is "ahead of pace" when more than 10% beyond that line (once a tenth of it is spent), and "over" past its amount. With rollover on, what is left carries into next month, and overspending comes out of it. A new budget suggests the average of your last three months, rounded up.
Recurring costs and what Ballast notices
Recurring items repeat every so many weeks, months or years, keep their day of the month through short months, and can record themselves automatically. Ballast also looks through your history for payments that repeat: the same payee, an amount within 10%, and gaps that are all close to a week, a month or a year. A place you simply visit often does not qualify.
Insights only appear with enough data to be fair: spending against the same point last month, the category that rose most, a purchase three times bigger than usual for its category, the most expensive day of the week over eight weeks, how much of last month's income you kept, and what your recurring costs come to in a year.
Reading a bank statement
- Text, not pictures. A PDF is read with pdf.js in this browser tab. Text runs are grouped into lines by their position, and the table is rebuilt from the column headings: numbers are placed by their right edge (amounts are right-aligned), dates by order, and wrapped descriptions joined to the line above. A CSV is read directly, with its delimiter worked out from the file.
- Columns. Headings like Posting Date, Value Date, Description, Debit, Credit and Balance are recognised, with or without a currency in them. Without headings, columns are inferred from their contents. You can change any of them before importing.
- The running balance check. Each row's balance must equal the previous balance plus that row's amount. When every row agrees, nothing was misread. When the amounts have no signs, the balance says which way the money went.
- No duplicates. Each line gets a fingerprint from its account, date, amount and description, so importing an overlapping statement adds only what is new. A line that matches something you added by hand, or a salary Ballast moved itself, is left unticked.
- Tidy names and categories. Card numbers, terminal codes and reference numbers are stripped, common merchants are recognised, and your corrections become rules.
Scanned statements (pictures of paper) have no text to read, and Ballast says so rather than guessing.
Read the code
Every calculation lives in src/lib as a plain function with tests beside it. The
source is on
GitHub
. See also privacy.