quantlab.runs.backtest_attribution.excess_decomposition#

quantlab.runs.backtest_attribution.excess_decomposition(strategy, gross, universe, benchmark, years)[source]#

Split the strategy’s annualised log growth over the benchmark into its three parts.

strategy is the value curve after costs, gross the same weights simulated without costs (None when the engine cannot), universe the equal-weighted universe (rebalanced_group_values with one group) and benchmark the benchmark’s (None without one). Each part is the difference of two curves’ annualized_log_growth: universe is universe over benchmark, selection gross over universe, costs strategy over gross, and total their sum, the strategy over the benchmark. Without a benchmark universe is left out and total is measured over the universe; without gross costs is left out and selection is the strategy over the universe.

Parameters:
strategy, universearray-like

Value curves on the window’s bars.

gross, benchmarkarray-like or None

Value curves on the window’s bars, or None.

yearsfloat

The window’s length in years.

Returns:
dict of str to float

universe (with a benchmark), selection, costs (with gross) and total.

Examples

>>> parts = excess_decomposition([1.0, 1.21], [1.0, 1.331], [1.0, 1.1], [1.0, 1.0], years=1.0)
>>> {k: round(v, 4) for k, v in parts.items()}
{'universe': 0.0953, 'selection': 0.1906, 'costs': -0.0953, 'total': 0.1906}