Install
$ agentstack add skill-brainbytes-dev-everything-claude-trading-portfolio-attribution ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Portfolio Performance Attribution
> Decomposing portfolio returns into allocation, selection, and factor contributions.
When to Activate
- User needs to explain why a portfolio outperformed or underperformed its benchmark
- Implementing Brinson-Fachler attribution for equity portfolios
- Building factor-based attribution using regression or risk models
- Performing fixed income attribution (duration, credit, curve)
- Linking single-period attribution across multiple periods
Core Concepts
What Is Attribution?
Attribution decomposes the active return (portfolio return minus benchmark return) into components that explain where and how value was added or lost. Two major frameworks:
- Holdings-based (Brinson): uses portfolio and benchmark weights and returns by sector/region
- Returns-based (factor regression): regresses portfolio returns on factor returns to identify exposures
- Risk-model-based: uses a multi-factor risk model to decompose returns into factor and specific components
Brinson-Fachler Attribution
Decomposes active return into three effects for each sector s:
Allocation Effect: did the manager overweight sectors that outperformed?
AE_s = (w_p,s - w_b,s) * (R_b,s - R_b)
Selection Effect: did the manager pick better stocks within each sector?
SE_s = w_b,s * (R_p,s - R_b,s)
Interaction Effect: combined effect of overweighting sectors where stock picks were also good
IE_s = (w_p,s - w_b,s) * (R_p,s - R_b,s)
Total active return: Rp - Rb = ΣAEs + ΣSEs + ΣIE_s
Where:
- wp,s, wb,s: portfolio and benchmark weight in sector s
- Rp,s, Rb,s: portfolio and benchmark return in sector s
- R_b: total benchmark return
Factor-Based Attribution
Uses a multi-factor risk model (e.g., Barra, Axioma, Northfield):
R_p - R_f = Σ (β_p,k - β_b,k) * f_k + α_specific
Where βp,k is the portfolio's exposure to factor k, and fk is the factor return. Decomposes into:
- Factor timing: return from active factor bets
- Specific return: stock-level alpha (idiosyncratic return)
Methodology
Step 1: Brinson Attribution Implementation
import pandas as pd
import numpy as np
def brinson_fachler(portfolio_weights, benchmark_weights,
portfolio_returns, benchmark_returns):
"""
Single-period Brinson-Fachler attribution by sector.
All inputs are Series indexed by sector.
"""
total_bench_return = (benchmark_weights * benchmark_returns).sum()
allocation = (portfolio_weights - benchmark_weights) * (benchmark_returns - total_bench_return)
selection = benchmark_weights * (portfolio_returns - benchmark_returns)
interaction = (portfolio_weights - benchmark_weights) * (portfolio_returns - benchmark_returns)
result = pd.DataFrame({
'port_weight': portfolio_weights,
'bench_weight': benchmark_weights,
'port_return': portfolio_returns,
'bench_return': benchmark_returns,
'allocation': allocation,
'selection': selection,
'interaction': interaction,
'total_active': allocation + selection + interaction
})
# Verify: sum of total_active should equal portfolio return - benchmark return
port_return = (portfolio_weights * portfolio_returns).sum()
bench_return = (benchmark_weights * benchmark_returns).sum()
assert abs(result['total_active'].sum() - (port_return - bench_return)) 8.2%}
Benchmark Return: {bench_ret:>8.2%}
Active Return: {active_ret:>8.2%}
--- Decomposition by Sector ---
{'Sector':8} {'Select':>8} {'Inter':>8} {'Total':>8}
{'-'*60}
"""
for sector, row in attribution_df.iterrows():
report += f" {sector:8.2%} {row['selection']:>8.2%} "
report += f"{row['interaction']:>8.2%} {row['total_active']:>8.2%}\n"
report += f" {'-'*60}\n"
report += f" {'TOTAL':8.2%} "
report += f"{attribution_df['selection'].sum():>8.2%} "
report += f"{attribution_df['interaction'].sum():>8.2%} "
report += f"{attribution_df['total_active'].sum():>8.2%}\n"
return report
Examples
Equity Attribution by Sector
# Sector weights and returns
sectors = ['Technology', 'Healthcare', 'Financials', 'Energy', 'Consumer']
port_w = pd.Series([0.35, 0.20, 0.15, 0.10, 0.20], index=sectors)
bench_w = pd.Series([0.28, 0.15, 0.18, 0.12, 0.27], index=sectors)
port_r = pd.Series([0.08, 0.05, 0.03, -0.02, 0.04], index=sectors)
bench_r = pd.Series([0.06, 0.04, 0.04, -0.01, 0.03], index=sectors)
result = brinson_fachler(port_w, bench_w, port_r, bench_r)
# Allocation to Tech (overweight in strong sector) = positive
# Selection in Tech (8% vs 6%) = positive
Interpreting Results
Key insights to surface:
- Was alpha from sector allocation (top-down) or stock selection (bottom-up)?
- Which sectors had the largest attribution? Is it consistent over time or a one-off?
- Is the interaction effect large? If so, the manager may be making correlated allocation and selection bets
- Does attribution match the stated investment process? (A bottom-up manager should show selection, not allocation)
Quality Gate
- [ ] Attribution sums exactly to total active return (no residual beyond rounding)
- [ ] Multi-period attribution uses a proper linking method (Carino, GRAP, or Menchero)
- [ ] Sector/region classification is consistent between portfolio and benchmark
- [ ] Transaction effects excluded from holdings-based attribution (or accounted for separately)
- [ ] Currency effects separated from local returns for international portfolios
- [ ] Factor-based attribution uses a risk model consistent with the portfolio's universe
- [ ] Interaction effect interpreted correctly — not lumped into allocation or selection arbitrarily
- [ ] Reported at multiple levels: total, sector, country, and individual security
- [ ] For fixed income: duration, curve, and spread effects isolated before reporting selection
- [ ] Attribution is stable and explainable — large unexplained residuals indicate model problems
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: brainbytes-dev
- Source: brainbytes-dev/everything-claude-trading
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.