Specific-ID lot selection minimising tax with cross-account wash-sale rules
Choose specific tax lots for a required sell list to minimise tax cost under short/long-term rates while avoiding wash-sale violations against recent and planned purchases across all accounts.
instruction.md
What the agent sees (CONVENTIONS.md is appended automatically)
Specific-ID lot selection with wash-sale rules
/app/input/required_sells.csv lists shares to sell per ticker in the taxable account. Using tax_lots.csv and tax_profile.yaml (short-term rate, long-term rate; holding period strictly greater than 365 days is long-term), choose lots to minimise total tax (gains taxed, losses credited at the applicable rate).
Wash-sale rule: a loss on a lot is disallowed if the same ticker or a substantially identical one (/app/policy/identical_pairs.csv) was bought within 30 days before the sale, or will be bought within 30 days after (planned buys in /app/input/planned_buys.csv and DRIP reinvestments in any account, including IRAs). Disallowed losses earn zero credit.
Write /app/output/lot_selection.csv (lot_id, shares_sold) and /app/output/tax_summary.json (st_gain, lt_gain, st_loss, lt_loss, disallowed_loss, total_tax).
Verification
reward.json metrics · weights sum to 1.00
| Metric | Weight | Check |
|---|---|---|
| total_tax | 0.5 | <= oracle + 0.01 USD. |
| wash_sale_violationsgate | 0.3 | No loss credited on a lot that triggers the rule. GATE at 0.2. |
| sums_consistent | 0.2 | Summary equals recomputation from lot_selection. |
Gates: wash_sale_violations. 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-lot-selection-wash-sale" version = "1.0.0" description = "Choose specific tax lots for a required sell list to minimise tax cost under short/long-term rates while avoiding wash-sale violations against recent and planned purchases across all accounts." keywords = ["etf", "portfolio", "rebalance", "tax-and-optimization", "tax-lots", "wash-sale", "optimization"] [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
- An IRA DRIP purchase of an identical pair within the window disallows a taxable loss.
- A lot acquired exactly 365 days ago is short-term.
- Partial lots are allowed.
- HIFO is not optimal when the highest-cost lot's loss would be disallowed.
Inputs
Fixtures mounted in the environment
- /app/portfolio/tax_lots.csv, /app/portfolio/transactions.csv, /app/portfolio/accounts.csv
- /app/policy/tax_profile.yaml, /app/policy/identical_pairs.csv
- /app/data/prices/
- /app/data/dividends.csvNeeded to predict DRIP buys in the 30-day window.
Outputs
What the verifier reads from /app/output
- /app/output/lot_selection.csvCSVLots and shares sold.
- /app/output/tax_summary.jsonJSONTax breakdown.
Anti-gaming
Lot ages, DRIP timing and identical pairs are seeded.
Oracle notes
solution/solve.sh must score 1.0 on five seeds
MILP over lot fractions with binary disallowance indicators.
Reviews (0)
Design review before a task is marked ready