Brinson–Fachler attribution with Cariño linking that reconciles exactly
Monthly Brinson–Fachler attribution versus the policy benchmark with Cariño geometric linking over 12 months, reconciling exactly to the active return.
instruction.md
What the agent sees (CONVENTIONS.md is appended automatically)
Attribution that reconciles
For the last 12 calendar months compute the household's monthly return by sleeve (buy-and-hold within month from start-of-month positions; treat any mid-month external flow as occurring at the start of the month) and the policy benchmark's sleeve returns (from the idx_<sleeve> columns of /app/data/benchmarks.csv) with benchmark weights from /app/policy/ips.yaml.
For each month and sleeve compute Brinson–Fachler effects: allocation = (w_p - w_b)(r_b_sleeve - r_b_total), selection = w_b (r_p_sleeve - r_b_sleeve), interaction = (w_p - w_b)(r_p_sleeve - r_b_sleeve). Link across months with Cariño logarithmic coefficients so that the sum of linked effects equals the 12-month geometric active return.
Write /app/output/attribution.json with per-month and total effects and a reconciliation block {active_return, sum_of_effects, residual}.
Verification
reward.json metrics · weights sum to 1.00
| Metric | Weight | Check |
|---|---|---|
| monthly_effects | 0.5 | abs 1e-8 for every month, sleeve and effect. |
| linked_totals | 0.3 | abs 1e-8. |
| reconciliation | 0.2 | |residual| < 1e-9. |
Harbor scaffold
Generated from this record — task.toml, Dockerfile, verifier, oracle stub
schema_version = "1.4" [task] name = "portfolio-agent-evals/pf-analyze-brinson-attribution" version = "1.0.0" description = "Monthly Brinson–Fachler attribution versus the policy benchmark with Cariño geometric linking over 12 months, reconciling exactly to the active return." keywords = ["etf", "portfolio", "analyze", "portfolio-analytics", "attribution", "geometric-linking", "reconciliation"] [metadata] author_name = "portfolio-agent-evals" difficulty = "hard" category = "quant-finance" tags = ["portfolio-analytics", "tier-3", "analyze", "multi-metric"] theme = "Portfolio Analytics & Exposure" tier = 3 reward_type = "multi-metric" [agent] timeout_sec = 1800.0 [verifier] timeout_sec = 180.0 [environment] # Offline by design: all data is synthetic and generated at build time. network_mode = "none" cpus = 2 memory_mb = 4096 storage_mb = 10240 build_timeout_sec = 900.0
Traps
Each must carry signal: a trap-blind solution must lose credit
- A mid-month contribution: flow-at-start convention changes sleeve weights for that month.
- The cash sleeve has a benchmark weight of 0 — selection is zero but allocation is defined.
- A sleeve present in the benchmark but empty in the portfolio.
- Cariño coefficients use log(1+R)/R with the limit at R = 0.
Inputs
Fixtures mounted in the environment
- /app/portfolio/transactions.csv, /app/portfolio/holdings.csv
- /app/data/prices/
- /app/data/benchmarks.csv
- /app/policy/ips.yaml
- /app/data/dividends.csv
Outputs
What the verifier reads from /app/output
- /app/output/attribution.jsonJSONMonthly and linked effects with reconciliation.
Anti-gaming
Flow timing and month set vary by seed.
Oracle notes
solution/solve.sh must score 1.0 on five seeds
Oracle follows Bacon (2008) chapter on Cariño linking.
Reviews (0)
Design review before a task is marked ready