Time-weighted return (TWR) answers "what happened to one rupee that was in this portfolio for the whole period?" It is deliberately blind to the size of the pot. The construction is mechanical: cut the period at every external cash flow, compute each sub-period's return on the value immediately before the flow, then chain-link the sub-period growth factors:
1 + TWR = (1 + r₁) × (1 + r₂) × … × (1 + rₙ)
External flows never enter a numerator or a denominator; they only tell you where to cut. This is why TWR is the manager-evaluation measure and why the GIPS standards require it for the composite returns a firm presents (see GIPS basics). The manager did not choose when the client wired money; holding her responsible for its timing would be measuring the wrong person.
How is money-weighted return calculated?
Money-weighted return (MWR) answers "what did the investor actually earn on the money he actually had at risk?" It is the internal rate of return of the full cash-flow series: the single periodic rate r that makes the present value of every contribution, withdrawal and the terminal value net to zero.
Σ CFₜ / (1 + r)ᵗ = 0
Now the flows are the whole point. Because the IRR weights each period by the capital at work in it, a large contribution just before a bad stretch drags the MWR down and a large contribution just before a good stretch lifts it, regardless of the manager's decisions. In the example portfolio, ₹3 crore arrived on 30 June and the very next quarter lost 6%. The manager's TWR is 14.94%; the investor's MWR is 8.51%; the 6.44-point gap is entirely a timing effect, and it is nobody's alpha and nobody's fault. (Worked Example 1 does both computations line by line.)
Advertisement
When should you use each one?
Two consequences follow immediately, and they are the whole practical content of the distinction:
- Never compare a TWR to an MWR. They are different questions. A manager whose TWR beats the index while her clients' MWR trails it does not have a performance problem; she has a client-behaviour problem, and the fix is advice, not a new stock picker.
- Never use TWR to judge a manager who controls the timing. This is the exception that swallows the rule in private markets. A buyout GP decides when to call capital and when to distribute; timing is the skill. Measuring her with a TWR strips out precisely the decision being judged. The GIPS standards recognise this and require a money-weighted return where the firm controls the external cash flows and the strategy has closed-end characteristics: fixed life, fixed commitment, or significant illiquid holdings. (Worked Example 7; the fund-economics machinery is PW1.02's.)
What is the Modified Dietz method?
Modified Dietz is the practical bridge. Before daily valuation was cheap, cutting the period at every flow was impossible, so the industry approximated the MWR with a formula that day-weights each flow instead of solving an IRR:
R = (EMV − BMV − CF) / (BMV + Σ wᵢ × CFᵢ), where wᵢ = (D − dᵢ) / D
D is the days in the period and dᵢ the days from the start to flow i, so wᵢ is the fraction of the period the flow was invested. The denominator is average invested capital, which is exactly the fix the 17.35% answer was missing. Modified Dietz is a money-weighted measure (a linear approximation to the IRR), and it is close when flows are small relative to the portfolio and returns are not violent. On our portfolio it gives 8.45% against the true IRR's 8.51%: a 6-basis-point approximation error on a period containing a flow worth 150% of the opening value. Under GIPS, Modified Dietz survives only as a legacy method for old periods; current practice values the portfolio on the flow date.
Modern Data Analysis: the Python way. Chain-linking is
(1 + r).prod() - 1over a pandas Series of sub-period returns; the MWR is a root-find,scipy.optimize.brentqon the NPV function ornumpy_financial.irrfor evenly spaced flows, withxirr-style day-count handling when the dates are irregular. Two traps that bite in production and that no error message will warn you about. First,numpy_financial.irrassumes equally spaced periods; feed it dated flows and it will return a confident, wrong number. Use an actual/365 day-count NPV and solve it yourself. Second,pandas.Series.std()defaults toddof=1(sample) whilenumpy.std()defaults toddof=0(population). On the twelve-quarter series in risk-adjusted performance measures that single default moves the standard deviation from 6.642 to 6.359 and the Sharpe ratio from 0.512 to 0.535: a difference big enough to reorder a manager ranking, produced by a keyword argument nobody typed. Always state yourddofexplicitly. The quant-code region's Data & Machine Learning branch builds the full vectorised pipeline; here, the point is that you must be able to reconcile whatever the library prints against a hand computation, because the library's defaults are not your conventions.