Skip to content

Brinson–Fachler Attribution (A/S/I)

1. Calculation Name

Brinson–Fachler Allocation, Selection, Interaction Attribution

2. Description and Mathematical Formula

Using Brinson–Fachler arithmetic attribution, performance is decomposed into:

  • Allocation effect: \( A_i = (w^P_i - w^B_i) \times (r^B_i - R^B) \)
  • Selection effect: \( S_i = w^B_i \times (r^P_i - r^B_i) \)
  • Interaction effect: \( I_i = (w^P_i - w^B_i) \times (r^P_i - r^B_i) \)

Where:

  • \( w^P_i, r^P_i \) are portfolio weights and returns
  • \( w^B_i, r^B_i \) are benchmark weights and returns
  • \( R^B = \sum_i w^B_i r^B_i \) is the total benchmark return
  • The active return \( R^P - R^B = \sum_i (A_i + S_i + I_i) \)

3. Input Sample Data

Segment \( w^P_i \) \( r^P_i \) \( w^B_i \) \( r^B_i \)
Government 35% 2.10% 40% 1.80%
Credit 30% 4.50% 25% 3.80%
Mortgages 15% 3.20% 20% 3.00%
High Yield 10% 6.50% 5% 5.00%
Cash 10% 0.50% 10% 0.40%

Benchmark return \( R^B = 2.56\% \).

4. Mathematical Solution

  • Allocation effects (bps):
    Government \(= (0.35 - 0.40) \times (1.80\% - 2.56\%) = +3.8\)
    Credit \(= (0.30 - 0.25) \times (3.80\% - 2.56\%) = +6.2\)
    Mortgages \(= (0.15 - 0.20) \times (3.00\% - 2.56\%) = -2.2\)
    High Yield \(= (0.10 - 0.05) \times (5.00\% - 2.56\%) = +12.2\)
    Cash \(≈ 0.0\)
  • Selection effects (bps):
    Government \(= 0.40 \times (2.10\% - 1.80\%) = +12.0\)
    Credit \(= 0.25 \times (4.50\% - 3.80\%) = +17.5\)
    Mortgages \(= 0.20 \times (3.20\% - 3.00\%) = +4.0\)
    High Yield \(= 0.05 \times (6.50\% - 5.00\%) = +7.5\)
    Cash \(= 0.10 \times (0.50\% - 0.40\%) = +1.0\)
  • Interaction effects (bps):
    Government \(= (0.35 - 0.40) \times (2.10\% - 1.80\%) = -1.5\)
    Credit \(= (0.30 - 0.25) \times (4.50\% - 3.80\%) = +3.5\)
    Mortgages \(= (0.15 - 0.20) \times (3.20\% - 3.00\%) = -1.0\)
    High Yield \(= (0.10 - 0.05) \times (6.50\% - 5.00\%) = +7.5\)
    Cash \(≈ 0.0\)
  • Totals:
    Allocation = 20.0 bps
    Selection = 42.0 bps
    Interaction = 8.5 bps
    Active return \(= 0.705\%\) (70.5 bps)

5. Sample Python and R Code

import pandas as pd

data = pd.DataFrame(
    {
        "segment": ["Government", "Credit", "Mortgages", "High Yield", "Cash"],
        "w_p": [0.35, 0.30, 0.15, 0.10, 0.10],
        "r_p": [0.021, 0.045, 0.032, 0.065, 0.005],
        "w_b": [0.40, 0.25, 0.20, 0.05, 0.10],
        "r_b": [0.018, 0.038, 0.030, 0.050, 0.004],
    }
)

R_b = (data["w_b"] * data["r_b"]).sum()
data["allocation"] = (data["w_p"] - data["w_b"]) * (data["r_b"] - R_b)
data["selection"] = data["w_b"] * (data["r_p"] - data["r_b"])
data["interaction"] = (data["w_p"] - data["w_b"]) * (data["r_p"] - data["r_b"])

totals = data[["allocation", "selection", "interaction"]].sum()
active = totals.sum()
print(data)
print(totals, active)
library(dplyr)

data <- tibble::tibble(
  segment = c("Government", "Credit", "Mortgages", "High Yield", "Cash"),
  w_p = c(0.35, 0.30, 0.15, 0.10, 0.10),
  r_p = c(0.021, 0.045, 0.032, 0.065, 0.005),
  w_b = c(0.40, 0.25, 0.20, 0.05, 0.10),
  r_b = c(0.018, 0.038, 0.030, 0.050, 0.004)
)

R_b <- sum(data$w_b * data$r_b)

data <- data %>%
  mutate(
    allocation = (w_p - w_b) * (r_b - R_b),
    selection = w_b * (r_p - r_b),
    interaction = (w_p - w_b) * (r_p - r_b)
  )

totals <- summarise(data,
  allocation = sum(allocation),
  selection = sum(selection),
  interaction = sum(interaction)
)
active <- sum(totals)
data
totals
active

6. Output Table

Segment Allocation (bps) Selection (bps) Interaction (bps)
Government +3.8 +12.0 -1.5
Credit +6.2 +17.5 +3.5
Mortgages -2.2 +4.0 -1.0
High Yield +12.2 +7.5 +7.5
Cash +0.0 +1.0 +0.0
Total +20.0 +42.0 +8.5

7. Conclusion

Brinson–Fachler attribution highlights whether excess performance comes from allocation tilts, security selection, or their interaction. This template aligns with FinFacts’ reporting views and is a reliable reference for QA, demos, and documentation.