Calculate investment performance independent of external cash flows.
Value at the start of the entire measurement period.
Period 1
Positive for deposits, negative for withdrawals.
Period 2
Period 3 (Final)
Final portfolio value at the end of the analysis.
Period 1 Return (HPR):–
Period 2 Return (HPR):–
Period 3 Return (HPR):–
Cumulative TWRR:–
Total Gain/Loss ($):–
Understanding Time Weighted Rate of Return (TWRR)
The Time Weighted Rate of Return (TWRR) is the standard method used in the investment management industry to measure the performance of a portfolio. Unlike simple return calculations, TWRR eliminates the distorting effects of cash inflows (deposits) and outflows (withdrawals) on the growth rate.
Why Use TWRR Instead of Simple Return or IRR?
If you use a simple return calculation (End Value – Start Value / Start Value) on a portfolio where you deposited a large sum of money halfway through the year, the return would appear artificially inflated simply because the account balance grew due to the deposit, not investment performance.
Similarly, the Internal Rate of Return (IRR) or Money Weighted Return is heavily influenced by the timing and size of cash flows. While IRR is useful for measuring an individual investor's actual experience, TWRR is superior for measuring the investment manager's performance because managers typically do not control when clients deposit or withdraw funds.
The TWRR Formula
TWRR breaks the investment timeframe into sub-periods based on when cash flows occur. The return for each sub-period is calculated, and then these returns are "chained" (geometrically linked) together.
Note: In this calculation method, the "Start Value" of a new period is equal to the "End Value" of the previous period PLUS any net cash flow that occurred at that break point.
Example Calculation
Consider an investor with the following portfolio activity:
Action
Amount / Value
Calculation Basis
Start (Jan 1)
$100,000
Initial Investment
End of Period 1 (June 30)
$110,000
Gain of $10,000 (10%)
Cash Flow
+$90,000
Deposit added. New Basis: $200,000
End of Period 2 (Dec 31)
$220,000
Gain of $20,000 on $200k base (10%)
Even though the portfolio value went from $100,000 to $220,000 (a 120% increase in dollars), the investment performance was actually steady at 10% per period.
A positive TWRR indicates growth driven by investment performance. Because TWRR is a geometric average, it accurately reflects the compound growth of the portfolio. Financial advisors and fund managers generally report TWRR to clients to demonstrate how well their strategy performed relative to market benchmarks, regardless of client deposit/withdrawal activity.
function calculateTWRR() {
// 1. Get DOM elements
var initialValueInput = document.getElementById('initialValue');
var p1EndValueInput = document.getElementById('p1EndValue');
var p1CashFlowInput = document.getElementById('p1CashFlow');
var p2EndValueInput = document.getElementById('p2EndValue');
var p2CashFlowInput = document.getElementById('p2CashFlow');
var p3EndValueInput = document.getElementById('p3EndValue');
var resultBox = document.getElementById('resultBox');
var resP1 = document.getElementById('resP1');
var resP2 = document.getElementById('resP2');
var resP3 = document.getElementById('resP3');
var resTotal = document.getElementById('resTotal');
var resGain = document.getElementById('resGain');
// 2. Parse Inputs
var startVal = parseFloat(initialValueInput.value);
var p1End = parseFloat(p1EndValueInput.value);
var p1Flow = parseFloat(p1CashFlowInput.value) || 0; // Default to 0 if empty
var p2End = parseFloat(p2EndValueInput.value);
var p2Flow = parseFloat(p2CashFlowInput.value) || 0; // Default to 0 if empty
var p3End = parseFloat(p3EndValueInput.value);
// 3. Validation
if (isNaN(startVal) || startVal 0) {
hpr2 = (p2End – basis2) / basis2;
basis3 = p2End + p2Flow;
hasP2 = true;
} else if (!isNaN(p2End) && basis2 0) {
hpr3 = (p3End – basis3) / basis3;
hasP3 = true;
} else if (!isNaN(p3End) && basis3 <= 0) {
alert("Calculation Error: The portfolio value dropped to zero or below after Period 2 cash flows.");
return;
}
// — Geometric Linking —
// (1 + r1) * (1 + r2) * (1 + r3) … – 1
var chain = (1 + hpr1);
if (hasP2) chain *= (1 + hpr2);
if (hasP3) chain *= (1 + hpr3);
var twrr = chain – 1;
// — Total Monetary Gain —
// This is tricky in TWRR context, but simple math is: Current Value – Net Invested Capital
// Net Invested = Initial + Flow1 + Flow2
var finalValue = hasP3 ? p3End : (hasP2 ? p2End : p1End); // Logic to find last known value
// Note: If P2 is entered but P3 is not, final value is P2End (before P2 flow? No, usually P2 flow is for P3).
// Let's assume standard reporting: Final value is the last Valuation entered.
var totalInvested = startVal + p1Flow + p2Flow;
// Note: We include flows only if the subsequent period exists or if it's the end of chain?
// Actually, simple gain = Final Holding Value – (Sum of all inputs).
// But if P1 flow happened, it's money in/out.
// Let's stick to strict Final Value – Net Invested.
// If user entered P1 Flow but no P2 End, the P1 Flow is essentially sitting in the account or withdrawn.
// We will calculate gain based on the last valid period end value.
var effectiveFinalValue = p1End;
var effectiveInvested = startVal;
if (hasP2) {
effectiveFinalValue = p2End;
effectiveInvested += p1Flow;
}
if (hasP3) {
effectiveFinalValue = p3End;
effectiveInvested += p2Flow;
}
var totalGain = effectiveFinalValue – effectiveInvested; // Approximation for display
// 5. Display Results
resultBox.style.display = 'block';
// Format Percentages
resP1.innerHTML = (hpr1 * 100).toFixed(2) + "%";
if (hasP2) {
resP2.innerHTML = (hpr2 * 100).toFixed(2) + "%";
document.getElementById('p2EndValue').parentNode.style.opacity = "1";
} else {
resP2.innerHTML = "N/A";
}
if (hasP3) {
resP3.innerHTML = (hpr3 * 100).toFixed(2) + "%";
} else {
resP3.innerHTML = "N/A";
}
resTotal.innerHTML = (twrr * 100).toFixed(2) + "%";
// Format Currency
var formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
// Just for visual context, usually TWRR doesn't focus on $ gain, but users like it.
// However, calculating absolute $ gain with complex flows is essentially (FinalVal – (Start + NetFlows)).
// Let's refine the Total Gain to be: LastValuation – (Start + Sum of Flows occuring BEFORE LastValuation).
// This is technically tricky because flow happens AFTER valuation in this UI.
// Wait, if P1End is 105k and Flow is +10k.
// If we stop at P1, Gain = 105k – 100k = 5k. The 10k flow hasn't been invested yet for a period.
// If we stop at P2. P2End 120k. Basis was 105+10=115.
// Gain P2 = 120 – 115 = 5k.
// Total Gain = 5k (P1) + 5k (P2) = 10k.
// Let's just suppress Total Gain if it's ambiguous, or display the TWRR prominently.
// Let's calculate purely TWRR focused.
// I will display a "Hypothetical Growth of $1000" instead of Gain, which is standard for TWRR.
var growthOf1k = 1000 * (1 + twrr);
resGain.innerHTML = formatter.format(growthOf1k) + " (Growth of $1,000)";
// Update label
document.querySelector('.result-row:last-child .result-label').innerText = "Hypothetical Value of $1,000:";
}