Random thoughts about budgets. Nothing coherent at the moment.

Requirements

Some top-level requirements:

  1. The ability to see the current state of things: How much money is in each account, taking into consideration future payments and goals
  2. The ability to add “events” such as:
    • Salary coming in
    • One-off payment
    • Recurring payment
    • Future payment
  3. The ability to have more than one account
  4. The ability to add goals: allocating enough to meet a future payment
  5. The ability to see the state at a given date
  6. The ability to transfer money between accounts

Number 4 is an extension of a future payment: It’s a future payment where the money is not allocated all up-front.

Number 5 is an extension of number 1.

Example

  • 1000 salary on the 1st of the month (recurring)
  • Gas bill on the 10th (60, recurring)
  • Shopping every week (80, recurring each Monday)
  • One off purchase (100, 15th)
  • Target of 2000 8 months away

I want to see that to meet the target, 250 has to be allocated each month. On the 25th the status will be:

  • Current state is 1000 - 250 - 60 - 80 * 3 - 100 = 350
  • Future payments: 80 next week, salary the week after

Numbers and dates are not precise, of course. So dealing with dates is important as well. Allocating money for future purchases happens ASAP.

Implementation

This is clearly a joke, but why not think about it?

Several object classes (not necessarily tied to a “class” in some programming language) jump to mind:

  1. Account - holds some information about the “real world” account
  2. Event - something that happens, it has a (start) date, in/out amount, description, recurrence
  3. Active event set - the set of all active events at a given point in time

An event could be connected to other events, for example “clone of”. We may start with a recurring event for a gas bill, but then change the amount at some point. The first event becomes inactive, the second becomes active, but we may want to remember that the second one was a clone of the first (not sure why, so maybe not important).

It may be possible to go pretty far with just that. We’ll see.

Budget vs. Actual

One possible addition is to split events to “planned” and “actual”. If the planned event is weekly shopping of 80 and the actual event is a one-off shopping of 76, then there is some discrepancy. The planned events define the budget. The actual events need to be taken into consideration because they are the reality, but there’s a question of how to capture the difference. More thought required.

Actual vs. Real

Even with actual events, there needs to be some connection to reality. I can update a spreadsheet all day long, but if that’s not what I have in my actual bank account, that’s not good. So there needs to be a way to say “Yes, up to this date it all matches”.

Future Goal

Let’s say that I have a future goal called “Holiday”. I want to save 2000 for the holiday, in 10 months’ time. In theory, that means putting aside 200 each month. So this month I’m happy with that 200, and I also find myself with an extra 50 which I can put towards the holiday. I allocate that 50, and suddenly I need to save 1750 in 9 months (whatever that is per month).

The following month I have unexpected expenses, and can’t afford the automatic allocation of 200. I can only afford 100. So that leave my with 1650 in 8 months. And so on.

About Holiday

Speaking of holidays, it’s not a single payment. Yes, I want to save 2000, but it’s for different things: hotel, car, food, etc. So when I make an actual hotel payment, I want to count it as part of the “holiday”. In other words, I’m happy to reduce the goal by tha amount I’m paying, because that’s what I saved for.

Different Aspects

So far, there’s quite a lot of stuff. I need a model that would work with all of those requirements (and more). “Events” (or “Transactions”) sounds good, but there should be a model for the actual budget.

Maybe some examples would help. Fake numbers ahead.

My salary is 1000. There’s a transaction on the first of each month, adding 1000 to the bank account. It’s a “template”, so can be changed, both as a template (permanent change) or once. So what’s important is the actual transaction - having a generator is fun, but it could also be done manually.

So maybe starting manually is the key. Let’s say that every transaction must be entered manually, to simplify the world.

The first transaction is +1000. The second transaction is -100 council tax (on the first of the month). The third is -75 for shopping on the 5th. I can enter those transactions and on the 6th I should have 825 in the bank. I check my account, and indeed 825. I mark everything as good (“reconciled”).

But that doesn’t give me any value. I have a bank account for that.

What I want is future transactions. That’s the key - I want to see on the 6th how much I have after future transactions. But the future isn’t known, so I can only estimate. And the future may have N transaction for a single planned one (so we can call the future one a “category” maybe).

An elaborate example:

  • +1000 / 1st (salary - reconciled)
  • -100 / 1st (council tax - actual, not reconciled)
  • -75 / 5th (shopping - planned)
  • -90 / 10th (gas bill - planned)
  • -75 / 12th (shopping - planned)
  • -65 / 15th (electricity bill - planned)
  • -75 / 19th (shopping - planned)
  • -80 / 22nd (home insurance - planned)
  • -75 / 26th (shopping - planned)
  • +1000 / 1st (salary - planned)

I’m on the 3rd. I can see the future transactions, and see that the total is -535, I have 900 at the moment (1000 - 100). So “free money” is 900 - 535 = 365.

Next Step

Time to start coding.

More Thoughts

The budget is the container of everything. We load and save a budget.

The budget contains;

  1. Accounts
  2. Rules

Accounts include starting balance (+ date) and transactions.

Rules

Let’s talk about rules for a second.

We have actual transactions. On a specific date, a specific amount was transferred between accounts (or between the external world and an account). That’s an actual, factual transaction.

Then we have everything else.

A planned transaction: Today is 2024-01-01, I am going to pay a gas bill on 2024-01-10. I think that it’s about 50, but it could change.

A planned recurring transaction: Once a week (on a Wednesday, unless it’s not possible), a sum of 50 is moved between my current account and my savings account.

A goal-oriented recurring transaction: I need to pay 1000 in a year’s time. That means (roughly) 85 a month. 85 x 12 = 1020, but 80 x 12 is not enough. So I want to set aside 85 a month, but it could fluctuate because maybe one month I really can only afford 40 towards my goal.

All of those are not real transactions. They may be “templates” (in the case of recurring transactions) or “plans”, or “virtual” transaction.

Virtual transaction can be actualised. A one-off is easy. I was going to play 40 on 2024-01-12, but it turned out to be 42 one day layer. But is it really easy? What does it look like?

The point is that once a virtual transaction is actualised, the original must disappear (or morph). A one-off virtual transaction can be actualised “in place”. We have one instance of a virtual transaction, and it becomes an actual transaction. This can be modelled using “planned” date/amount and “actual” date/amount. As long as there is no actual data, it’s a virtual transaction. If there is only actual data, it was never virtual.

But what about recurring transactions? One option is to always have a limit, and virtualise every transaction. In other words, I have a large expense that I’m saving for - a deposit on a house. I need to save for 4 years, and I’m putting 200 a month away. I want to track this, so I virtualise 48 transactions, and each of them is actualised at some point. I can look into the future and see where I stand. But that may be a bit wasteful. But then, even once a week for 20 years ends up as only 1040 virtual transactions. Still a bit wasteful, there’s a lot of shared information there, and they should all be tied together.

The other extreme is a single “recurring rule”, which can be extrapolated to infinity. Every week you say? Let’s see what happens in 2429. But that’s a bit ridiculous. This makes it a bit hard to actualise - if a transaction is actualised, we no longer care about the virtual version. But this change cannot be done “in place” because there is only one rule. Even if we create a virtual transaction and actualise it, how do we then ignore the rule for that transaction?

An example: We have a rule that says “200 every 3rd of the month”. In January it’s fine. But in February I can only afford 180. I want to see a single 180 transaction, not two transaction - one actual (180) and one virtual (200) from the rule. So somehow we have to suppress the rule-related one. We could just say “this 180 payment (on the 5th) should have been 200 on the 3rd” and tie them together using date + amount (+ rule id). But feels a bit flimsy.

One additional option is to have a rule and virtual transactions. The rule itself has a name, maybe a target, a description, etc. and the virtual transactions simply point to the rule and have a date. Rules must be limited, but 1000 virtual transaction doesn’t take much storage. We may not need to instantiate everything - the rule can run forever, but we may only want to instantiate what we care about.

So the solution may be this:

  1. We have a rule with start date, recurrence, amount, name, description, id etc.
  2. When we actualise the rule, we instantiate up to that date. So the rule knows how far it has been instantiated. Up to that point, we only show instances. From that point, we use the rule. The instantiation point moves with time.

This way, we can see what happens in 2429 if we want to, because we’re not actualising anything. If I actualise (confirm + maybe amend) the payment in May, everything up to May is instantiated. The last point may have been February, so we instantiate March, April and May, and then actualise May and leave March and April virtual.

This is a reasonable compromise.

Allocation

Now we have actual transactions and virtual transactions, plus rules to generate virtual transactions.

But something is still missing. Let’s say that I want to pay my home insurance in a single payment, because it’s cheaper. But I also want to prepare for it in some way - put some money aside each month so that when the date arrives I have the money there.

I could create a “goal” of paying 300 in a year’s time. That’s 25 a month, which I can put to one side. I can create a transaction of 25 from my account to … where? And it’s not a real transaction, because the money is not going to go from my account - it’s going to stay there, it’s just that I shouldn’t touch it.

It’s a sort of “reserve” transaction. I need to separate the actual amount that I have in the account from the available / reserved amounts. A reserve transaction moves money inside an account from “available” to “reserved”. I can also pay from the reserve.

Pots

Maybe instead of just “reserved”, we can have pots. A pot is “reserved” - we can reserve money (move it from “available” to a specific pot) and we can also use money from a pot. There’s an option between:

  1. Transactions are “real” - they always move actual money (if they’re virtual, they’ve just not been actualised yet)
  2. Transactions can also be associated with one or more reservations.

But option 2 is just complicating things.

Let’s say that I have a savings account, and I have three targets in mind: 1. Buy a car (long term). 2. Build a reserve of 2000 for a rainy day. 3. Just general savings, just in case.

I can associate a transaction that moves 200 to the savings account with two additional reservations: one for the car (50), one for the rainy day (120). The rest (30) just lands in the savings account to become “available” there.

But that’s a weird transaction. I want more flexibility with my reservations than with the transactions. Why should they be coupled?

So instead I can have a car pot and a rainy day pot. Unrelated to that, I move money to my savings account (because I can get better interest). I allocate pot money from wherever I want. I manage to save 10000 for a car in the car pot. Then I go an buy a car. I know that I have that money, but it could be in different accounts. The pot should tell me where the money is. I can make transfers between accounts to have all the money in one account - note that it’s still in a pot! But then I can “release” the money from the pot, make it available, and buy a car. The pot is back to zero, and I have a car.

So “pots” and accounts are orthogonal. Moving money to a pot is “reserving”. It’s not a transaction.

There are some issues though: Can I pay for something if there’s not enough “available” money? Can “available” money ever be negative? If not, do I have to release money from a pot before I transfer it between accounts, for example? That would be the simple model:

  1. Release money from the pot
  2. Transfer
  3. Add money back to the pot

That would allow the pot to always track where the money is. If I have 50 available in my savings, plus 100 in a pot, and I am allowed to move 150 to another account, then suddently everything is broken. The pot has reserved money that isn’t there.

But this is quite strict. What if I allow available to become negative?

  • 100 in a pot
  • 50 available

I move 150 to my current account:

  • 100 in a pot
  • -100 available in savings
  • 250 available in current account

A minus is not good. I release the money:

  • 0 in a pot
  • 0 available in savings
  • 250 available in current account

I then add money to the pot from the current account

  • 100 in a pot
  • 0 available in savings
  • 150 available in current account

So it’s all good. Pots know where the money is coming from. Available money can be negative. I can sort everything after the fact (or before, if I want to).

Next Steps

  1. Add transactions - actual and virtual
  2. Add rules to generate virtual transactions and to be used in predictions
  3. Add pots and reservations

Transactions

Pragmatic question: should there be a single class for transactions (both actual and virtual), or should there be a transaction base class, and actual / virtual derived classes?

What are the operations?

  • Create a new transaction (actual / virtual):
    • For an actual transaction, we need a date and an amount
    • For a virtual transaction, we need a date and an amount
  • Actualise a virtual transaction - would that actually create a new object? It would have to if modelled using inheritance.
  • Getters
  • Update amount / date
  • Tell whether it’s virtual or not

This feels safe to model using inheritance. I’ll give it a go.

Downside is that storing “dynamically polymorphic” objects is just a bit more complicated…

Not convinced. A single class may be “messy” but it’s so much simpler. So much. I just need to get this done. There is one thing though. An actual transaction has actual detaisl: accounts, amount, date. We may want to also know, if it was actualised from a virtual transaction, what that transaction was. A virtual transaction may be created from a rule - we may want to know that as well.

We could have a source field - it could be either a virtual transaction (if the transaction is actual), or a rule (if the transaction is virtual). It could also be nothing (if it’s a manual transaction - virtual or actual). In addition, we need to know if a transaction is virtual or not, and whether it’s been actualised. So it’s a tristate: virtual, actualised, actual. When a virtual transaction is actualised, it actually creates a new actual transaction, initialises its source, and sets itself as actualised.

Actualised transactions are disregarded when looking at the budget, but they’re there for an audit trail.

This simplifies stuff a bit.