Tax-loss harvesting into partner ETFs with exposure and wash-sale guards
Identify and execute tax-loss harvests into designated partner ETFs while maintaining sleeve exposure and respecting the wash-sale window in both directions.
instruction.md
What the agent sees (CONVENTIONS.md is appended automatically)
Tax-loss harvesting
Find lots in the taxable account with unrealised loss >= 1,000 USD and >= 2% of cost. Sell them and buy the designated partner ETF (tlh_pairs in ips.yaml) so that each sleeve's household weight moves by less than 1%. Do not harvest a lot if the ticker or its identical pair was bought within the last 30 days anywhere in the household, and record a 31-day blackout for each harvested ticker in /app/output/blackout.json. Respect the single-ETF concentration limit in ips.yaml.
Estimate tax alpha = harvested loss x applicable rate. Write trades.csv and /app/output/harvest_report.json.
Verification
reward.json metrics · weights sum to 1.00
| Metric | Weight | Check |
|---|---|---|
| harvested_loss | 0.4 | >= 98% of oracle's harvestable loss with no ineligible lot included. |
| violations_zerogate | 0.3 | Wash-sale and concentration violations = 0. GATE at 0.2. |
| exposure_maintained | 0.3 | Every sleeve moves < 1%. |
Gates: violations_zero. A gate failure caps or zeroes the trial reward regardless of other metrics.
Harbor scaffold
Generated from this record — task.toml, Dockerfile, verifier, oracle stub
schema_version = "1.4" [task] name = "portfolio-agent-evals/pf-tax-loss-harvest-swap" version = "1.0.0" description = "Identify and execute tax-loss harvests into designated partner ETFs while maintaining sleeve exposure and respecting the wash-sale window in both directions." keywords = ["etf", "portfolio", "rebalance", "tax-and-optimization", "tax-loss-harvesting", "wash-sale", "exposure-management"] [metadata] author_name = "portfolio-agent-evals" difficulty = "hard" category = "quant-finance" tags = ["tax-and-optimization", "tier-3", "rebalance", "multi-metric"] theme = "Tax-Aware & Constrained Optimization" tier = 3 reward_type = "multi-metric" [agent] timeout_sec = 2400.0 [verifier] timeout_sec = 240.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
- The partner ETF is already held; the swap can breach the concentration limit for one seed group — harvest partially.
- Threshold is per lot, not per position.
- A recent IRA purchase of an identical pair blocks one otherwise-attractive harvest.
Inputs
Fixtures mounted in the environment
- /app/portfolio/
- /app/policy/ips.yaml, /app/policy/tax_profile.yaml, /app/policy/identical_pairs.csv
- /app/data/prices/
Outputs
What the verifier reads from /app/output
- /app/output/trades.csvCSVHarvest sells and partner buys.
- /app/output/harvest_report.jsonJSONLots harvested, tax alpha.
- /app/output/blackout.jsonJSONBlackout windows.
Anti-gaming
Loss lots, partner holdings and recent buys are seeded.
Oracle notes
solution/solve.sh must score 1.0 on five seeds
Enumerate eligible lots, then LP for partial harvest under the concentration cap.
Reviews (0)
Design review before a task is marked ready