Skip to content

Methods reference#

Every method ships with its mathematical statement, a primary academic citation, and a clickable URL in the source module. Open the file, read the formula, verify the number.

Method map#

flowchart LR
    In["Segments<br/>(wp, wb, Rp, Rb)"]
    BHB[["BHB<br/>A = (wp-wb)·Rb"]]
    BF[["Brinson-Fachler<br/>A = (wp-wb)·(Rb-Rb_tot)"]]
    KS[["Karnosky-Singer<br/>+ local / currency split"]]
    Single["PeriodAttribution<br/>A + S + I = excess"]
    In --> BHB --> Single
    In --> BF --> Single
    In -->|"+ local_return<br/>+ currency_return"| KS --> Single
    Single -->|"≥ 2 periods"| Link{{"link_carino<br/>link_grap<br/>link_frongello<br/>link_menchero<br/>link_geometric"}}
    Link --> Linked["LinkedAttribution<br/>multi-period identity"]

Single-period#

Brinson-Hood-Beebower (3-effect)#

For each segment \(i\):

\[ \begin{aligned} A_i &= (w_{p,i} - w_{b,i}) \cdot R_{b,i} \\ S_i &= w_{b,i} \cdot (R_{p,i} - R_{b,i}) \\ I_i &= (w_{p,i} - w_{b,i}) \cdot (R_{p,i} - R_{b,i}) \end{aligned} \]
\[\sum_i (A_i + S_i + I_i) = R_p - R_b\]
  • Brinson, G. P., Hood, L. R., & Beebower, G. L. (1986). "Determinants of Portfolio Performance." Financial Analysts Journal, 42(4), 39-44. DOI 10.2469/faj.v42.n4.39.
  • Free CFA reprint: CFA Institute PDF.
  • Source: src/pybrinson/single_period/bhb.py.
from pybrinson import bhb
result = bhb(segments, period="2024-Q1", parents=None)

Brinson-Fachler (3-effect)#

Same decomposition as BHB except allocation is evaluated against the benchmark's total return:

\[A_i = (w_{p,i} - w_{b,i}) \cdot (R_{b,i} - R_b)\]

Selection and interaction are unchanged; totals coincide with BHB because \(\sum_i (w_{p,i} - w_{b,i}) \cdot R_b = 0\).

  • Brinson, G. P., & Fachler, N. (1985). "Measuring Non-U.S. Equity Portfolio Performance." Journal of Portfolio Management, 11(3), 73-76. DOI 10.3905/jpm.1985.409005.
  • Source: src/pybrinson/single_period/fachler.py.
from pybrinson import fachler
result = fachler(segments, period="2024-Q1")

Karnosky-Singer currency attribution (4-effect)#

For multi-currency portfolios. See the currency guide.

\[ \begin{aligned} M_i &= (w_{p,i} - w_{b,i})(R^L_{b,i} - R^L_{b,\text{tot}}) \\ S_i &= w_{b,i}(R^L_{p,i} - R^L_{b,i}) \\ C_i &= (w_{p,i} - w_{b,i})(c_i - c_{b,\text{tot}}) \\ I_i &= (w_{p,i} - w_{b,i})(R^L_{p,i} - R^L_{b,i}) \end{aligned} \]

pybrinson pins the additive Karnosky-Singer convention: \(R_{p,i} = R^L_{p,i} + c_i\) (continuously compounded).

  • Karnosky, D. S., & Singer, B. D. (1994). Global Asset Management and Performance Attribution. CFA Institute Research Foundation. Free PDF.
  • Source: src/pybrinson/single_period/currency.py.
from pybrinson import currency_attribution
result = currency_attribution(segments, period="2024-Q1")

Multi-period linking#

flowchart TD
    Start{"Reporting in<br/>geometric excess?"}
    Start -- Yes --> Geom[["link_geometric<br/>(Bacon)"]]
    Start -- No --> Region{"Regulatory / audit<br/>context?"}
    Region -- "North-American<br/>default" --> Carino[["link_carino"]]
    Region -- "European / French<br/>institutional" --> Grap[["link_grap"]]
    Region -- "Match published<br/>Frongello 2002 numerics" --> Fron[["link_frongello"]]
    Region -- "Uniform scaling<br/>(Menchero 2000/2004)" --> Men[["link_menchero"]]

All five linking functions consume a Sequence[PeriodAttribution] and return a LinkedAttribution. They require at least 2 periods and all periods must come from the same single-period method.

Cariño log-smoothing#

\[ A^{\text{linked}} = \sum_t k_t \cdot A_t \qquad k_t = \frac{\ln(1 + R_{p,t}) - \ln(1 + R_{b,t})}{R_{p,t} - R_{b,t}} \big/ K \]

where \(K\) is the global coefficient computed from compounded returns. Requires \(R_t > -1\) every period.

  • Cariño, D. R. (1999). "Combining Attribution Effects Over Time." Journal of Performance Measurement, 3(4), 5-14. Russell Investments PDF.
  • Source: src/pybrinson/linking/carino.py.

GRAP factor linking#

Additive linking using period factors \(F_t = \prod_{s \ne t} (1 + R_{p,s}) \cdot \prod_{s > t} (1 + R_{b,s}) \cdot \prod_{s < t} (1 + R_{b,s})\). The GRAP 1997 technical note is the original reference.

  • Source: src/pybrinson/linking/grap.py.

Frongello recursive#

\[C_t = C_{t-1} \cdot (1 + R_{b,t}) + A_t \cdot (1 + R_{p, t-1}^{\text{cum}})\]

Uses the "prefix portfolio × suffix benchmark" convention (the published form, pp. 4-5 of Frongello 2002).

  • Frongello, A. (2002). "Attribution Linking: Proofed and Clarified." Journal of Performance Measurement, 7(1). Author PDF.
  • Source: src/pybrinson/linking/frongello.py.

Menchero optimised#

Uniform scaling:

\[A^{\text{linked}} = M \cdot \sum_t A_t + \sum_t \alpha_t \cdot A_t\]

where \(M\) and \(\alpha_t\) are solved to close the identity. Patent US 7,249,082 B2 expired 2024-02-18.

  • Menchero, J. (2000). "An Optimized Approach to Linking Attribution Effects Over Time." Journal of Performance Measurement, 5(1), 36-42.
  • Menchero, J. (2004). "Multiperiod Arithmetic Attribution." Financial Analysts Journal, 60(4). DOI 10.2469/faj.v60.n4.2638.
  • Source: src/pybrinson/linking/menchero.py.

Geometric (Bacon)#

Multiplicative:

\[A^{\text{geom}}_t = \frac{A_t}{1 + R_{b,t}}, \quad S^{\text{geom}}_t = \frac{S_t + I_t}{1 + R_{b,t} + A_t}\]
\[ (1 + A^{\text{linked}})(1 + S^{\text{linked}}) - 1 = \frac{1 + R_p^{\text{cum}}}{1 + R_b^{\text{cum}}} - 1 \]

Interaction is folded into selection by construction.

  • Bacon, C. R. (2008). Practical Portfolio Performance Measurement and Attribution, 2nd ed., chap. 6.
  • Source: src/pybrinson/linking/geometric.py.

Multi-level hierarchies#

Any depth. Pass a parents={parent: grandparent} mapping. Allocation, selection, and interaction roll up additively: each parent is the sum of its descendants. See the hierarchies guide.

  • Source: src/pybrinson/_hierarchy.py.

Consistency invariants#

pybrinson includes a cross-method consistency suite (tests/consistency/test_cross_method.py):

  • BHB and Brinson-Fachler totals agree algebraically.
  • All four additive linkers (Cariño, GRAP, Frongello, Menchero) reproduce the same compounded portfolio and benchmark returns.
  • Geometric linking reproduces the same compounded returns but its excess is the multiplicative \((1 + R_p) / (1 + R_b) - 1\), not the arithmetic difference.
  • All linkers are exercised on parametrised random inputs.