Where Money Docs

How the numbers work

How net worth is worked out

Every figure on the Net Worth tab comes from the records you typed on the Records tab. Nothing on this page is derived from an imported transaction, and nothing here reaches the spending numbers in What counts as spending.

Net worth#

net worth = financial + owned − owed

Balances are always typed as positive numbers. The asset class decides the sign, which means there is no way to get it wrong by typing a minus in the wrong place — and no way for a mortgage to be accidentally added to the total.

Allocation is measured over the financial pot only#

The percentages, the bar and the drift panel all use financial holdings — cash, deposits, bonds, funds, crypto — and leave property, vehicles and debt out.

That is not an oversight. A share is there to inform a decision, and the only decision in reach is how to split the money you can actually move. In a picture where the flat is 62 % of everything, nothing else is legible and the number answers no question you asked. The headline figure above the bar covers the other reading; the Net worth | Financial only toggle switches between them.

Shares are rounded per class, so they can add up to 100 % give or take a hundredth — the same rounding the spending dashboard's bar uses.

Added, and return#

Every record splits the stretch since the one before it into what you put in and what happened by itself:

return = (this record's value − the previous record's value) − added

The stretch is however long you left it. Two records a fortnight apart measure a fortnight; two a year apart measure a year. Nothing is annualised and nothing is interpolated — the ledger reports the days you wrote down and says nothing about the days between them.

Added is money you moved. Return is everything else: market moves, interest, exchange rates. That split is the one thing a snapshot spreadsheet cannot tell you, and the reason the tab asks for two numbers instead of one.

For a debt it works out on its own. A mortgage of 100 000 that falls to 99 500 in a stretch you paid 1 000 off gives a return of −500 — which is exactly what the interest cost you. A payment that goes entirely to principal shows a return of zero.

The classes a return is measured on#

That formula is right for an ETF and wrong for a current account. A current account's balance falls because the rent left and rises because you were paid; neither is a gain, and neither is a loss. Left alone, a record written after you spent 2 000 złoty reported a 2 000 złoty loss, and the Performance panel ranked the account you live out of beside the fund you invest in.

So each class carries a flag: is a return measured on money held here? It ships off for Cash PLN, Cash EUR and Cash USD and on for everything else, and you set it per class on the Holdings tab — a class you add is presumed to earn one.

A class you stop measuring loses nothing else. Its money still counts in net worth, still counts in the allocation, and still takes the contributions you type. What changes is where its movement is reported:

value change − added, in a class that earns nothing = cash moved

Cash moved is a band of its own in Where the change came from, and the decomposition still adds up to the last grosz. The Performance panel prints not measured rather than 0,00 for those holdings, because a current account did not fail to earn — it was never asked to.

The Return % ignores them entirely: cash left in the denominator would divide an ETF's gain by a balance the ETF never had access to. And the entry pane's "you did not contribute this" warning skips them too — a guard that fired every time you paid rent would be dismissed unread on the day it mattered.

Restatements: when a holding appears or vanishes#

The formula above needs one more term, or it lies badly at the edges.

The first record you add the flat you have always owned to, the balance jumps by 400 000. Read naively, that is a 400 000 market gain — for typing a row. Deleting a row is the mirror image: a catastrophic loss for tidying up.

So a holding's first record is an opening, not a gain, and its return is zero. A holding that was in the last record and is not in this one is a closing. Both are restatements — the picture changed, not the money — and the header carries a restated tag on any record where one happened, with the holdings named.

Opening a genuinely new account is not affected. If you open a brokerage account and put 5 000 into it, that 5 000 is a contribution, and the opening is zero.

Everything adds up:

change in net worth = added + return + cash moved + openings − closings

A first record that says what it cost#

The rule above is a refusal: the app will not call an arrival a gain, because it cannot tell one from the other. But sometimes you can. A holding you have been paying into for years arrives carrying a profit its provider has already worked out, and zeroing it throws that away permanently — there is no earlier record to measure back to and there never will be.

So an opening can name a cost. What it cost arrives; the rest was earned:

value = basis + return, on the record a holding opens in

The basis takes the place the previous record's balance would have held, which is what makes the whole thing fall out of the formulas already here rather than needing new ones:

valueaddedopeningreturn
an ETF worth 48 900 that cost 43 466,6748 900,000,0043 466,675 433,33

The identity is untouched — 48 900 = 0 + 5 433,33 + 43 466,67 − 0 — and the restatement is now the capital rather than the whole balance. Because the basis stands where a previous balance would, it is also the whole capital the Return % is measured over, so the rate the app prints back is exactly the rate you typed.

Three things follow, and they are all deliberate:

  • The percentage is measured against the cost, not against the balance. That is what your broker means by "+12,5 %", and reproducing that figure is the entire point of typing it.
  • There is no contribution on such a record. "What you put in since the record before this one" has no referent when there is no record before this one, so the amount column holds the cost instead of competing with it.
  • Nothing is annualised. The stretch a pre-ledger profit covers is not on file — it might be six years or six weeks — so the rate is printed as it stands, with no /yr beside it. See how long the rate covers.

A basis is only ever read on the record a holding opens in. Write an earlier record later and that record becomes the opening; the basis on the newer one stops being read and it goes back to being measured against the balance before it, which is the honest answer once one exists.

Everything else is unchanged. A holding that names no cost is still an opening with a return of zero, which is why the flat you have always owned is still not a 400 000 gain.

Return %#

A percentage is measured against the capital that was actually working, with the stretch's contribution given half the stretch's weight.

Dividing by the opening balance instead would be wrong twice. It divides by zero on a holding that started in this record, and it flatters the stretch in which you double a position: 300 earned on a 10 000 holding you added 10 000 to is 3,0 % against the opening balance and 2,0 % against the average, and only the second is a rate anyone could have earned.

A truer time-weighted return would need to know the dates the money moved on. This ledger holds one figure per holding per record by design, so half the stretch is the best assumption available, and the standard one. Write more often and the assumption gets smaller, which is the honest way to make a rate more accurate here.

How long the rate covers, and what it is in a year#

Once records can fall on any date, a bare percentage says almost nothing: +0,4 % over a fortnight and +0,4 % over a quarter are the same number and nothing like the same news. So every rate on the screen names the stretch it covers — +0,02 % over 15 days — and the holding drill carries a Days column for the same reason.

Beside it, where the stretch can carry the arithmetic, sits the figure that is comparable: the same rate carried out to a year, compounded — ≈ +0,5 %/yr. The performance panel switches its whole column between the two with Over the range / Per year.

Two rules keep that honest:

  • Nothing under a month is annualised. Raising a stretch to the power of 365/days multiplies whatever noise is in it: a holding that moved 17 % in a fortnight extrapolates to four digits, which compares nothing to anything. A month caps that multiplier at twelve — the same extrapolation every annualised monthly return makes. Under thirty days the app prints the period figure alone and says why.
  • A per-year figure is an extrapolation, never a forecast. It is what the stretch would come to if it repeated all year, which nothing does. It is there to compare two stretches of different lengths, and for nothing else.

Each row is annualised over the span its own return covers, not over the window you picked. A holding whose first record inside a 12-month window measures back to a record before that window is measured over the longer span — using the shorter one would quietly inflate every rate on the panel.

Over a range, the returns and the capital are each summed and divided once. That keeps the panel additive — a class's return is the sum of its holdings' returns — which matters more here than a purer rate, because every figure on this screen is meant to be checkable against the ones around it.

Where there was no capital to earn a return on, the app prints — rather than a percentage. A class nothing is measured on prints — always.

"vs 3 Mar", not "vs last time"#

Every comparison is against the previous record, whichever day that is, and the screen always names it. If you wrote in June and then not until August, August is measured against June. Nothing is interpolated and no date is invented.

The timeline#

Net worth over time puts days on the axis: a point per record, spaced by the dates you actually wrote, with a second line for money in — everything your net worth is made of except what it earned by itself.

That second line is what makes the picture readable without a single percentage. The gap between the two lines is your cumulative return in złoty, by construction rather than by a second calculation that could disagree with the first. Where the lines run parallel you were saving; where they spread you were earning; where they close you were losing.

The scale does not start at zero, and both ends of it are printed. A column starts at zero or its length lies — a line does not, because the mark is a position rather than a length, and anchoring a 700 000 portfolio at zero would draw the 30 000 that moved as a flat line in the top eighth of the box.

A segment joins two records and claims nothing about the days between them. There is no data there; the line is a reading aid, and the dots are where the ledger actually knows something.

Currency#

Every figure is stored and shown in PLN. A holding in EUR or USD is converted once, at the rate for that record's date, and the result is stored with the record — so a later correction to the rate table cannot rewrite what you already recorded. See the valuation date.

Because the conversion happens per record, a rate move shows up as return: if your euro balance did not change but the euro did, that is a real change in what you are worth in złoty, and the app reports it as one.

What is deliberately not modelled#

  • No detail between records. One figure per holding per record, so no true time-weighted return is possible on this data and none is claimed.
  • No transaction history per holding. This ledger holds balances and contributions, not the trades behind them.
  • No targets, rebalancing advice or forecasting. The app reports what happened; it holds no opinion about what should.
  • No currency other than PLN to view it in.

Where Money is independent software, not connected to any bank, and its figures are not a substitute for your bank's own statements. Privacy, disclaimer & terms.