Skip to content

Time-Weighted Return

1. Calculation Name

Time-Weighted Rate of Return (TWR)

2. Description and Mathematical Formula

The time-weighted return neutralizes the impact of external cash flows by breaking the period into sub-periods bounded by flows and geometrically chaining the returns.

For sub-period \( k \):

  • \( V_{k,0} \) = market value at the start of sub-period \( k \)
  • \( V_{k,1} \) = market value just before the next external flow
  • \( r_k = \frac{V_{k,1} - V_{k,0}}{V_{k,0}} \)

The TWR over \( n \) sub-periods is

\[ R_{\text{TWR}} = \prod_{k=1}^{n} (1 + r_k) - 1. \]

3. Input Sample Data

Sub-period Start Date End Date Start MV (USD) End MV before Flow (USD) Net Flow at End (USD)
1 2024-01-01 2024-01-07 1,000,000 1,030,000 +50,000
2 2024-01-07 2024-01-15 1,080,000 1,150,000 -20,000
3 2024-01-15 2024-01-25 1,130,000 1,160,000 +10,000
4 2024-01-25 2024-01-31 1,170,000 1,180,000 0
Ending Value 2024-01-31 1,180,000

4. Mathematical Solution

  • Sub-period returns:
    \( r_1 = (1{,}030{,}000 - 1{,}000{,}000) / 1{,}000{,}000 = 3.00\% \)
    \( r_2 = (1{,}150{,}000 - 1{,}080{,}000) / 1{,}080{,}000 = 1.77\% \)
    \( r_3 = (1{,}160{,}000 - 1{,}130{,}000) / 1{,}130{,}000 = 2.65\% \)
    \( r_4 = (1{,}180{,}000 - 1{,}170{,}000) / 1{,}170{,}000 = 0.85\% \)
  • Chain link:
    \( R_{\text{TWR}} = (1.0300) \times (1.0177) \times (1.0265) \times (1.0085) - 1 = 8.53\% \)

5. Sample Python and R Code

import pandas as pd
import numpy as np

data = pd.DataFrame(
    {
        "period": [1, 2, 3, 4],
        "start_mv": [1_000_000, 1_080_000, 1_130_000, 1_170_000],
        "end_mv": [1_030_000, 1_150_000, 1_160_000, 1_180_000],
    }
)

data["return"] = (data["end_mv"] - data["start_mv"]) / data["start_mv"]
twrr = np.prod(1 + data["return"]) - 1
print(f"TWR: {twrr:.4%}")
library(dplyr)

data <- tibble::tibble(
  period = 1:4,
  start_mv = c(1000000, 1080000, 1130000, 1170000),
  end_mv = c(1030000, 1150000, 1160000, 1180000)
)

data <- data %>%
  mutate(ret = (end_mv - start_mv) / start_mv)

twrr <- prod(1 + data$ret) - 1
scales::percent(twrr, accuracy = 0.01)

6. Output Table

Metric Value
Time-Weighted Return 8.53%
Number of Linked Periods 4
Product of (1 + r_k) 1.0853

7. Conclusion

TWR isolates manager skill by neutralizing the impact of external cash flows. This template mirrors the FinFacts desktop output, making it easy to validate chain-linking and to embed the same logic into factsheets or LLM responses.