The question with two answers#
"My account is up $12,000 this year. What is my return?"
That sounds like one question. It is actually two. One asks how well your investments performed. The other asks how well your dollars did. When you deposit or withdraw money during the year, the two answers diverge, sometimes dramatically. Understanding why is the single most useful piece of portfolio math you can learn.
Why simple percent change lies#
The naive calculation divides the change in value by the starting value. That works only when no money moves in or out.
Watch it break. You start the year with $10,000. By June 1 the market has carried it to $11,000, a real 10% gain. On June 1 you deposit $10,000 of savings, bringing the account to $21,000. Over the second half the market slips 5%, and you end the year at $19,950.
| Date | Event | Account value |
|---|---|---|
| Jan 1 | Start | $10,000 |
| Jun 1 | Market gain of 10% | $11,000 |
| Jun 1 | Deposit $10,000 | $21,000 |
| Dec 31 | Market loss of 5% | $19,950 |
The naive math says ($19,950 - $10,000) / $10,000 = 99.5%. Absurd. Most of that "gain" is your own deposit. Subtracting the deposit from the top ($19,950 - $20,000) / $10,000 = -0.5% is also wrong, because the two halves of the year operated on different amounts of money. Neither number describes what actually happened: the market went up 10%, then down 5%.
What time-weighted return measures#
Time-weighted return (TWR) is the industry-standard fix. It chops the period into daily segments, computes each day's return with that day's cash flow removed from the base, and chains the results together.
V_t is the portfolio value on day t and CF_t is the net external cash flow that arrived that day. Pyx uses the start-of-day convention: a deposit counts in the day's base before measuring growth. On the day your $10,000 lands, the base becomes $11,000 + $10,000 = $21,000, the value is $21,000, and the day's return is exactly zero. The deposit cancels out of the math entirely.
For the example above: 1.10 × 0.95 - 1 = 4.5%. That is the honest answer to "how well did my choices perform." It is the number you can fairly compare against SPY, against a fund, or against last year, because it is immune to when and how much you deposited.
Deposits are not gains. TWR is built so that moving your own money into the account can never move the return.
What money-weighted return measures#
Money-weighted return (MWR) answers the other question: how well did my actual dollars do? It is the internal rate of return (IRR) of your cash flows, the single annual rate that makes your deposits grow into your ending value. Timing matters here on purpose. A big deposit right before a rally boosts MWR. The same deposit right before a dip drags it down.
Run the same example. You put in $10,000 on January 1 and $10,000 on June 1, and finished with $19,950. The rate that reconciles those flows works out to about -0.3% per year. Your choices earned 4.5% time-weighted, but your biggest dollar arrived just in time for the losing half, so your money lost slightly.
Both numbers are true. They answer different questions.
| Time-weighted (TWR) | Money-weighted (MWR) | |
|---|---|---|
| Answers | Did I pick good investments? | Did my dollars grow? |
| Deposit timing | Ignored by construction | Counted deliberately |
| Compare against benchmarks | Yes, this is the fair one | No |
| Matches broker "personal return" | Rarely | Usually |
Under the hood Pyx computes MWR as an XIRR: it solves for the rate where the net present value of every cash flow is zero, using Newton's method with a bisection fallback. When the math admits more than one valid rate (which can happen with large interim withdrawals), Pyx picks the root nearest 0%, the one that matches a broker statement. Year fractions use days / 365.25. The calculation is rejected when the starting value is under $1 and capped at 1000% per year, so degenerate inputs show as unavailable instead of nonsense.
Annualized return and the short-window trap#
To compare a 7-month return against an annual benchmark, you annualize it:
A 6% return over 200 days annualizes to about 11.2%. Useful. But the same formula turns a lucky 2% week into roughly 180% per year. The shorter the window, the more the exponent amplifies noise. Treat annualized figures on windows under a year as a unit conversion, not a forecast.
How Pyx shows each return#
The Performance page has two chart modes. Value mode plots dollars, so deposits appear as jumps, which is honest about what the account held. Return mode plots the chained TWR, so deposits vanish and only market performance remains. The benchmark overlay always compares in Return mode, because comparing your dollar value against an index makes no sense.
The KPI strip above the chart shows both families side by side for the selected window:
- Time-Weighted is the chained daily TWR. It measures your invested securities: uninvested cash and cash interest are excluded, so the number reflects what your holdings did, not how much cash sat idle.
- Money-Weighted is the XIRR of your external flows over the window.
- Annualized applies the 365.25-day formula to the window's total return.
- Alpha is your window return minus the benchmark's return over the same window, as a simple difference.
When the two headline returns disagree, read it as information, not error. TWR above MWR means your deposit timing worked against you. MWR above TWR means your timing helped. Neither says anything about what to do next, but together they tell you whether the gap came from the market or from the calendar.