Skip to content

Modified Dietz Return

1. Calculation Name

Modified Dietz Money-Weighted Return

2. Description and Mathematical Formula

The modified Dietz method measures the money-weighted return over a period while accounting for the timing and size of external flows. Each flow is weighted by the proportion of the period that capital is invested.

Let:

  • \( B \) = beginning market value
  • \( E \) = ending market value
  • \( F_j \) = external flow \( j \) occurring on day \( d_j \) (where \( d_j = 0 \) is the period start)
  • \( T \) = total number of days in the period
  • \( w_j = \frac{T - d_j}{T} \) = weight applied to flow \( j \)

The modified Dietz return \( R_{\text{MD}} \) is

\[ R_{\text{MD}} = \frac{E - B - \sum_j F_j}{B + \sum_j w_j F_j} \]

3. Input Sample Data

Event Date Cash Amount (USD) Notes
Beginning Market Value 2024-01-01 1,000,000 Portfolio opening balance
Contribution 2024-01-05 50,000 Client top-up (day 4)
Withdrawal 2024-01-15 -20,000 Mid-month rebalance (day 14)
Contribution 2024-01-25 10,000 Income sweep (day 24)
Ending Market Value 2024-01-31 1,080,000 Valuation after fees

4. Mathematical Solution

  • Total flows: \( 50{,}000 - 20{,}000 + 10{,}000 = 40{,}000 \)
  • Weighted flows:
    \( 50{,}000 \times \frac{26}{30} = 43{,}333.33 \)
    \( -20{,}000 \times \frac{16}{30} = -10{,}666.67 \)
    \( 10{,}000 \times \frac{6}{30} = 2{,}000.00 \)
    Sum of weighted flows \( = 34{,}666.67 \)
  • Numerator: \( 1{,}080{,}000 - 1{,}000{,}000 - 40{,}000 = 40{,}000 \)
  • Denominator: \( 1{,}000{,}000 + 34{,}666.67 = 1{,}034{,}666.67 \)
  • Return: \( R_{\text{MD}} = \frac{40{,}000}{1{,}034{,}666.67} = 0.03866 \)3.87%

5. Sample Python and R Code

import pandas as pd

data = pd.DataFrame(
    {
        "event": ["BOP", "Flow", "Flow", "Flow", "EOP"],
        "date": pd.to_datetime(
            ["2024-01-01", "2024-01-05", "2024-01-15", "2024-01-25", "2024-01-31"]
        ),
        "amount": [1_000_000, 50_000, -20_000, 10_000, 1_080_000],
    }
)

start = data.loc[0, "date"]
end = data.loc[len(data) - 1, "date"]
period_days = (end - start).days

flows = data.iloc[1:-1].copy()
flows["days"] = (flows["date"] - start).dt.days
flows["weight"] = (period_days - flows["days"]) / period_days

B = data.loc[data["event"] == "BOP", "amount"].iloc[0]
E = data.loc[data["event"] == "EOP", "amount"].iloc[0]

weighted_flows = (flows["amount"] * flows["weight"]).sum()
net_flows = flows["amount"].sum()

return_md = (E - B - net_flows) / (B + weighted_flows)
print(f"Modified Dietz return: {return_md:.4%}")
library(dplyr)
library(lubridate)

data <- tibble::tibble(
  event = c("BOP", "Flow", "Flow", "Flow", "EOP"),
  date = as_date(c("2024-01-01", "2024-01-05", "2024-01-15", "2024-01-25", "2024-01-31")),
  amount = c(1000000, 50000, -20000, 10000, 1080000)
)

start <- data$date[1]
end <- data$date[n()]
period_days <- as.numeric(end - start)

flows <- data %>%
  slice(2:(n() - 1)) %>%
  mutate(
    days = as.numeric(date - start),
    weight = (period_days - days) / period_days
  )

B <- data$amount[1]
E <- data$amount[n()]

weighted_flows <- sum(flows$amount * flows$weight)
net_flows <- sum(flows$amount)

return_md <- (E - B - net_flows) / (B + weighted_flows)
scales::percent(return_md, accuracy = 0.01)

6. Output Table

Metric Value
Modified Dietz Return 3.87%
Net External Flows 40,000
Weighted Capital Base 1,034,666.67

7. Conclusion

The modified Dietz template captures capital-weighted performance while respecting cash flow timing. Use this structure when you need a quick sanity check against custodial money-weighted returns or when documenting validation test cases in FinFacts.