Skip to content

Fixed Income Effects

1. Calculation Name

Fixed Income Factor Effects (Income, Roll, Curve, Spread, FX, Selection)

2. Description and Mathematical Formula

The effects plugin breaks absolute performance into additive components derived from portfolio-level key-rate exposures:

\[ \mathrm{Total\ Return} = \mathrm{Income} + \mathrm{Roll} + \mathrm{Curve} + \mathrm{Spread} + \mathrm{FX} + \mathrm{Selection} \]

Each component is computed from mappings such as DV01 (curve), SDV01 (spread), and FX notional. For example:

  • Roll \( = \sum_{k} \mathrm{RollDV01}_{k} \times \Delta \text{roll}_{k} \)
  • Curve \( = \sum_{k} \mathrm{KRD}_{k} \times \Delta y_{k} \)
  • Spread \( = \sum_{k} \mathrm{SDV01}_{k} \times \Delta s_{k} \)

3. Input Sample Data

Date Income (bps) Roll (bps) Curve (bps) Spread (bps) FX (bps) Selection (bps) Total Return (bps) DV01 Total SDV01 Total
2024-01-05 12.5 4.3 -1.2 3.8 0.5 2.1 22.0 145 90
2024-01-12 12.7 4.1 -0.8 4.2 0.4 1.9 22.5 146 91
2024-01-19 12.6 3.9 -0.5 3.6 -0.2 2.0 21.4 144 88
2024-01-26 12.8 3.5 -1.0 4.5 -0.1 2.2 21.9 143 87
2024-02-02 13.0 3.2 -0.7 4.0 0.3 2.4 22.2 142 89

4. Mathematical Solution

  • Row check (2024-01-05):
    \( 12.5 + 4.3 - 1.2 + 3.8 + 0.5 + 2.1 = 22.0 \) bps
  • DV01/SDV01 columns track interest-rate and spread sensitivity totals used to derive roll/curve/spread components.
  • Horizon totals:
  • Income sum = 63.6 bps
  • Roll sum = 19.0 bps
  • Curve sum = -4.2 bps
  • Spread sum = 20.1 bps
  • FX sum = 0.9 bps
  • Selection sum = 10.6 bps
  • Total return sum = 109.0 bps
  • The equality holds for each row and in aggregate, providing a consistent decomposition.

5. Sample Python and R Code

import pandas as pd

data = pd.DataFrame(
    {
        "date": pd.to_datetime(["2024-01-05", "2024-01-12", "2024-01-19", "2024-01-26", "2024-02-02"]),
        "income": [12.5, 12.7, 12.6, 12.8, 13.0],
        "roll": [4.3, 4.1, 3.9, 3.5, 3.2],
        "curve": [-1.2, -0.8, -0.5, -1.0, -0.7],
        "spread": [3.8, 4.2, 3.6, 4.5, 4.0],
        "fx": [0.5, 0.4, -0.2, -0.1, 0.3],
        "selection": [2.1, 1.9, 2.0, 2.2, 2.4],
    }
)

components = ["income", "roll", "curve", "spread", "fx", "selection"]
data["total"] = data[components].sum(axis=1)

totals = data[components + ["total"]].sum()
print(data)
print(totals)
library(dplyr)

data <- tibble::tibble(
  date = as.Date(c("2024-01-05", "2024-01-12", "2024-01-19", "2024-01-26", "2024-02-02")),
  income = c(12.5, 12.7, 12.6, 12.8, 13.0),
  roll = c(4.3, 4.1, 3.9, 3.5, 3.2),
  curve = c(-1.2, -0.8, -0.5, -1.0, -0.7),
  spread = c(3.8, 4.2, 3.6, 4.5, 4.0),
  fx = c(0.5, 0.4, -0.2, -0.1, 0.3),
  selection = c(2.1, 1.9, 2.0, 2.2, 2.4)
)

components <- c("income", "roll", "curve", "spread", "fx", "selection")
data <- data %>%
  mutate(total = rowSums(across(all_of(components))))

totals <- summarise(data, across(all_of(c(components, "total")), sum))
data
totals

6. Output Table

Component Sum (bps)
Income 63.6
Roll 19.0
Curve -4.2
Spread 20.1
FX 0.9
Selection 10.6
Total Return 109.0

7. Conclusion

The fixed-income effects view translates complex exposure data into an intuitive factor breakdown. This template mirrors the plugin’s table layout, making it a solid reference for report authors and QA engineers validating curve or spread mappings.