Fixed Income Active Attribution¶
1. Calculation Name¶
Fixed Income Active Attribution (Carry/Curve/Spread/FX/Selection)
2. Description and Mathematical Formula¶
The active attribution plugin decomposes the excess return of a fixed-income portfolio into component effects using key rate durations, spread sensitivities, and FX exposures.
For each factor \( f \):
- Portfolio contribution \( C^P_f \)
- Benchmark contribution \( C^B_f \)
- Active effect \( C^{A}_f = C^P_f - C^B_f \)
Underlying calculations derive \( C^P_f \) and \( C^B_f \) by multiplying factor exposures (DV01, spread DV01, FX notional) by observed factor moves.
3. Input Sample Data¶
| Component | Portfolio Contribution (bps) | Benchmark Contribution (bps) |
|---|---|---|
| Carry | 35.2 | 28.7 |
| Curve | 12.4 | 10.1 |
| Spread | 58.0 | 44.5 |
| FX | 4.2 | 6.0 |
| Selection | 18.9 | 12.5 |
4. Mathematical Solution¶
- Active effects:
Carry \(= 35.2 - 28.7 = 6.5\) bps
Curve \(= 12.4 - 10.1 = 2.3\) bps
Spread \(= 58.0 - 44.5 = 13.5\) bps
FX \(= 4.2 - 6.0 = -1.8\) bps
Selection \(= 18.9 - 12.5 = 6.4\) bps - Total active return \( = 6.5 + 2.3 + 13.5 - 1.8 + 6.4 = 26.9 \) bps
- Expressed as percentage: \( 0.269\% \) excess performance for the horizon.
5. Sample Python and R Code¶
import pandas as pd
data = pd.DataFrame(
{
"component": ["Carry", "Curve", "Spread", "FX", "Selection"],
"portfolio_bps": [35.2, 12.4, 58.0, 4.2, 18.9],
"benchmark_bps": [28.7, 10.1, 44.5, 6.0, 12.5],
}
)
data["active_bps"] = data["portfolio_bps"] - data["benchmark_bps"]
data["active_pct"] = data["active_bps"] / 10000
total_active = data["active_bps"].sum() / 10000
print(data)
print(f"Total excess return: {total_active:.4%}")
library(dplyr)
data <- tibble::tibble(
component = c("Carry", "Curve", "Spread", "FX", "Selection"),
portfolio_bps = c(35.2, 12.4, 58.0, 4.2, 18.9),
benchmark_bps = c(28.7, 10.1, 44.5, 6.0, 12.5)
)
data <- data %>%
mutate(
active_bps = portfolio_bps - benchmark_bps,
active_pct = active_bps / 10000
)
total_active <- sum(data$active_bps) / 10000
data
scales::percent(total_active, accuracy = 0.01)
6. Output Table¶
| Component | Active Contribution (bps) |
|---|---|
| Carry | +6.5 |
| Curve | +2.3 |
| Spread | +13.5 |
| FX | -1.8 |
| Selection | +6.4 |
| Total | +26.9 |
7. Conclusion¶
FinFacts’ active attribution distills how rates, spreads, currencies, and security selection drive excess performance. Use this template when documenting investment commentary or validating the plugin against spreadsheet prototypes.