Calculate the Time-Weighted Rate of Return for your investment portfolio.
The value of the portfolio at the very beginning.
Period 1
Period 2
Period 3
Period 4
Cumulative TWRR:0.00%
Final Portfolio Value:$0.00
Period Breakdown:
Understanding Time-Weighted Rate of Return
The Time-Weighted Rate of Return (TWRR) is the standard method used in the investment industry to measure the performance of a portfolio. Unlike simple return calculations, TWRR eliminates the distorting effects of cash inflows (deposits) and outflows (withdrawals).
Why it matters: If you deposit a large sum of money into your account right before a market rally, a simple return calculation would artificially inflate your performance percentage. TWRR separates the timing of your cash flows from the actual investment performance.
How TWRR is Calculated
The calculation involves breaking down the investment horizon into sub-periods based on when cash flows occur. For each sub-period, a Holding Period Return (HPR) is calculated. These returns are then geometrically linked (compounded) to determine the total return.
The formula for a single period return is:
HPR = (End Value – (Start Value + Net Cash Flow)) / (Start Value + Net Cash Flow)
Or more simply derived from growth factors:
Growth Factor = End Value / (Start Value + Net Cash Flow)
The total TWRR is calculated by multiplying these Growth Factors:
Period 1: The portfolio grows to $105,000. The investor then deposits $10,000.
Return: ($105,000 – $100,000) / $100,000 = 5.0%
Period 2: Starting with $115,000 ($105k + $10k), the portfolio drops to $110,000.
Return: ($110,000 – $115,000) / $115,000 = -4.35%
The Money-Weighted return might look effectively flat, but TWRR links the periods:
(1 + 0.05) × (1 – 0.0435) – 1 = 0.43% Total Return.
TWRR vs. Money-Weighted Return (IRR)
While TWRR isolates investment skill, Money-Weighted Return (or IRR) measures the actual growth of the client's money, heavily influenced by the timing of deposits. Use TWRR to compare funds or managers; use IRR to understand your personal wealth growth.
function calculateTWRR() {
// 1. Get Initial Value
var initialVal = parseFloat(document.getElementById('initialValue').value);
if (isNaN(initialVal)) {
alert("Please enter a valid Starting Portfolio Value.");
return;
}
// 2. Initialize Variables
var cumulativeGrowth = 1.0;
var currentStart = initialVal;
var breakdownHTML = "";
var periodsFound = false;
var finalValue = initialVal;
// 3. Loop through 4 periods
for (var i = 1; i <= 4; i++) {
var flowId = "p" + i + "Flow";
var endId = "p" + i + "End";
var cashFlow = parseFloat(document.getElementById(flowId).value);
var endValue = parseFloat(document.getElementById(endId).value);
// Treat empty inputs as 0 for flow, check validity for End Value
if (isNaN(cashFlow)) cashFlow = 0;
// If endValue is entered, process this period
if (!isNaN(endValue)) {
periodsFound = true;
// Invested Amount = Start of Period + Cash Flow occurring at start/during
// Note: Standard Modified Dietz often assumes flow is weighted,
// but for simple sub-period linking (True TWRR), we assume flow happens before measurement of end value.
var investedCapital = currentStart + cashFlow;
if (investedCapital === 0) {
breakdownHTML += "
Period " + i + ": Skipped (Zero capital invested)
";
currentStart = endValue; // Reset for next period
continue;
}
// Calculate Growth Factor for this period
// Growth Factor = Ending Value / (Beginning Value + Cash Flow)
var growthFactor = endValue / investedCapital;
var periodReturn = (growthFactor – 1) * 100;
// Update Cumulative Growth
cumulativeGrowth *= growthFactor;
// Log breakdown
breakdownHTML += "
";
// Set up next period start
currentStart = endValue;
finalValue = endValue;
}
}
if (!periodsFound) {
alert("Please fill in at least Period 1 details.");
return;
}
// 4. Final Calculations
var totalTwrr = (cumulativeGrowth – 1) * 100;
// 5. Display Results
document.getElementById('totalTwrr').innerHTML = totalTwrr.toFixed(2) + "%";
document.getElementById('finalValueDisplay').innerHTML = "$" + finalValue.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
document.getElementById('breakdownList').innerHTML = breakdownHTML;
// Show result area
document.getElementById('result-area').style.display = 'block';
}