Brinson-Fachler#
Abstract interface and concrete implementations for the Brinson-Fachler attribution methodology (see Attribution Methodology for the conceptual background), plus the PyArrow table-reshaping utilities used by the Arrow implementation.
- class BrinstonFachlerInterface(returns_investible_assets: DataFrame, portfolio_weights: DataFrame, benchmark_weights: DataFrame)[source]#
Bases:
object
- class BrinstonFachlerAttribution(returns_investable_assets: DataFrame, complete_portfolio_weights: DataFrame, complete_benchmark_weights: DataFrame)[source]#
Bases:
BrinstonFachlerInterface
Abstract interface for Brinson-Fachler return attribution using PyArrow Tables.
Defines the contract that concrete Brinson-Fachler implementations must satisfy: computing single-period attribution for a given date and aggregating single-period results into a time series.
- class BrinstonFachlerArrowInterface(returns_investible_assets: Table, portfolio_weights: Table, benchmark_weights: Table)[source]#
Bases:
objectAbstract interface for Brinson-Fachler attribution using PyArrow Tables.
Defines the contract for computing single-period and multi-period Brinson-Fachler return attribution, decomposing active return into allocation, selection, and interaction effects.
- Parameters:
returns_investible_assets (pa.Table) – Asset returns table with a date column and one column per asset containing period returns as float64.
portfolio_weights (pa.Table) – Portfolio weight table with a date column and one column per asset containing portfolio weights as float64.
benchmark_weights (pa.Table) – Benchmark weight table with a date column and one column per asset containing benchmark weights as float64.
- abstractmethod brinson_fachler_model(date: str) tuple[Table, Table][source]#
Calculate the Brinson-Fachler attribution model for a single date.
Decomposes the active return (portfolio minus benchmark) into allocation, selection, and interaction effects for each asset.
- Parameters:
date (scalar) – The date for which to calculate the attribution. Must match a value present in the date column of the input tables.
- Returns:
detail_table (pa.Table) – Per-asset attribution with columns:
asset,portfolio_weights,benchmark_weights,returns_data,portfolio_returns,benchmark_returns,alpha,allocation,selection,interaction.totals_table (pa.Table) – Single-row summary with columns:
date,portfolio_returns,benchmark_returns,alpha,allocation,selection,interaction.
- abstractmethod time_series_calculation() None[source]#
Calculate the Brinson-Fachler attribution across all available dates.
Iterates over dates common to portfolio weights and benchmark weights, computing the single-period model for each, and concatenates the totals into a time-series table.
- Returns:
detail_dict (dict) – Mapping of each date to its per-asset
pa.Tabledetail breakdown.totals_table (pa.Table) – Concatenated totals across all dates with columns:
date,portfolio_returns,benchmark_returns,alpha,allocation,selection,interaction.
Concrete Brinson-Fachler return attribution implementation using PyArrow.
Implements BrinstonFachlerArrowInterface by decomposing active
portfolio return into allocation, selection, and interaction effects at
the asset level for each period, then aggregating across time.
- class BrinstonFachlerArrowAttribution(returns_investable_assets: Table, complete_portfolio_weights: Table, complete_benchmark_weights: Table, date_column: str = 'date')[source]#
Bases:
BrinstonFachlerArrowInterfaceBrinson-Fachler return attribution implementation using PyArrow.
Decomposes active portfolio return into allocation, selection, and interaction effects at the asset level for each period, then aggregates across time.
- Parameters:
returns_investable_assets (pa.Table) – Asset returns with a
date_columnand one float64 column per asset.complete_portfolio_weights (pa.Table) – Portfolio weights with a
date_columnand one float64 column per asset. Rows should sum to 1.0 for each date.complete_benchmark_weights (pa.Table) – Benchmark weights with a
date_columnand one float64 column per asset. Rows should sum to 1.0 for each date.date_column (str, default
"date") – Name of the date column common to all input tables.
- detail_table#
Per-asset detail from the most recent
brinson_fachler_modelcall.- Type:
pa.Table
- totals#
Single-row totals from the most recent
brinson_fachler_modelcall.- Type:
pa.Table
- df#
Concatenated totals time series after
time_series_calculation.- Type:
pa.Table
- output_dict#
Mapping of date to per-asset detail table after
time_series_calculation.- Type:
dict
- brinston_fach_indexes#
Cumulative attribution indexes after
attribution_plots.- Type:
pa.Table
- attribution_plots() None[source]#
Plot cumulative Brinson-Fachler attribution effects.
Produces a 3-panel figure:
Cumulative portfolio vs benchmark returns.
Cumulative alpha.
Cumulative allocation, selection, and interaction effects.
Must be called after
time_series_calculation.Sets Attributes#
- brinston_fach_indexespa.Table
Cumulative sums of all attribution columns, keyed by date.
- brinson_fachler_model(date: str) tuple[Table, Table][source]#
Calculate the Brinson-Fachler attribution for a single date.
Decomposes the active return into allocation, selection, and interaction effects for every asset, then sums to produce portfolio-level totals.
- Parameters:
date (scalar) – Target date matching a value in the date column.
- Returns:
detail_table (pa.Table) – Per-asset breakdown with columns:
asset,portfolio_weights,benchmark_weights,returns_data,portfolio_returns,benchmark_returns,alpha,allocation,selection,interaction.totals_table (pa.Table) – Single-row aggregate with columns:
date,portfolio_returns,benchmark_returns,alpha,allocation,selection,interaction.
- time_series_calculation() None[source]#
Run Brinson-Fachler attribution across all common dates.
Finds dates present in both portfolio and benchmark weights, runs
brinson_fachler_modelfor each date that also has return data, and concatenates results.Sets Attributes#
- dfpa.Table
Concatenated totals time series with columns:
date,portfolio_returns,benchmark_returns,alpha,allocation,selection,interaction.- output_dictdict
Mapping of each date to its per-asset
pa.Tabledetail.
Conversion utilities for reshaping PyArrow tables into the format expected by the Brinson-Fachler Arrow attribution engine.
Provides functions equivalent to table_conversion.py but without converting to pandas — all operations stay in PyArrow.
- compute_returns_from_prices_arrow(prices_table: Table, date_column: str) ReturnsTable[source]#
Compute percentage returns from a prices table.
Equivalent to
prices_df.pct_change(fill_method=None)— the first row is kept with null values so the date range stays aligned with the original prices table (and therefore with the weights tables).- Parameters:
prices_table (pyarrow.Table) – Prices table containing a date column and one or more numeric asset price columns.
date_column (str) – Name of the column in prices_table containing the dates. It’s passed through unchanged and always renamed to
"date"in the output, regardless of its original name.
- Returns:
Wrapper around a table with the same columns and row count as prices_table, where each asset column holds period-over-period percentage returns and the first row is null.
- Return type:
- portfolio_table_to_arrow(table: Table) PortfolioWeights[source]#
Transpose a wide portfolio/benchmark weights table into attribution format.
This is the PyArrow equivalent of
portfolio_table_to_pandas, which doesset_index("Ticker").T.- Parameters:
table (pyarrow.Table) – Wide-format weights table with columns
[Ticker, date1, date2, ...], one row per ticker and one column per date. Date column names are parsed as"%Y-%m-%d", falling back to"%d/%m/%Y"if that fails.- Returns:
Wrapper around a table with columns
[date, asset1, asset2, ...], i.e. one row per date and one column per ticker.- Return type:
- pyarrow_prices_to_attribution_format(table: Table, date_column: str) Table[source]#
Reshape a prices table into the attribution format.
The date column is cast to a
timestamptype and all remaining (numeric) columns are cast tofloat64.- Parameters:
table (pyarrow.Table) – Prices table containing a date column and one or more numeric asset price columns.
date_column (str) – Name of the column in table containing the dates. It’s cast from a
"%Y-%m-%d"string (if not already a timestamp type) and always renamed to"date"in the output, regardless of its original name.
- Returns:
Table with columns
[date, asset1, asset2, ...], wheredateis oftimestamp("ns")type and every asset column isfloat64.- Return type:
pyarrow.Table
- returns_table_to_arrow(table: Table) ReturnsTable[source]#
Transpose a wide returns table into attribution format.
Same transpose logic as
portfolio_table_to_arrow(), but wraps the result in aReturnsTable(no weight constraints).- Parameters:
table (pyarrow.Table) – Wide-format returns table with columns
[Ticker, date1, date2, ...], one row per ticker and one column per date. Date column names are parsed as"%Y-%m-%d", falling back to"%d/%m/%Y"if that fails.- Returns:
Wrapper around a table with columns
[date, asset1, asset2, ...], i.e. one row per date and one column per ticker.- Return type: