Minimum-turnover trade list restoring all bands (MILP with semi-continuous trades)
Solve the minimum-turnover trade list that brings every sleeve within bands under whole-share and cash constraints, verified by optimality gap against a MILP oracle.
instruction.md
What the agent sees (CONVENTIONS.md is appended automatically)
Minimum turnover to restore bands
Find integer share trades minimising the sum of |traded notional| subject to: every sleeve within its IPS band post-trade (weights on the post-trade total including cash; trading costs excluded from the denominator), cash >= buffer, no shorts, and each trade either 0 or at least 250 USD notional.
Write trades.csv and /app/output/solution.json {turnover, solver, gap_claimed}. scipy (HiGHS) is available; heuristics are acceptable if they reach the gap.
Verification
reward.json metrics · weights sum to 1.00
| Metric | Weight | Check |
|---|---|---|
| feasibilitygate | 0.4 | All constraints. GATE at 0.2. |
| objective_gap | 0.6 | turnover <= 1.005 x oracle: full; linear to 0 at 1.10 x oracle. |
Gates: feasibility. 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-opt-min-turnover-milp" version = "1.0.0" description = "Solve the minimum-turnover trade list that brings every sleeve within bands under whole-share and cash constraints, verified by optimality gap against a MILP oracle." keywords = ["etf", "portfolio", "rebalance", "tax-and-optimization", "milp", "optimization", "constraint-modelling"] [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 = 300.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 semi-continuous minimum notional needs binary indicators; relaxing it yields infeasible tiny trades.
- The cash sleeve has its own band.
- Weights denominator excludes costs by instruction — including them shifts the answer.
Inputs
Fixtures mounted in the environment
- /app/portfolio/holdings.csv, /app/portfolio/accounts.csv
- /app/data/prices/
- /app/policy/ips.yaml
Outputs
What the verifier reads from /app/output
- /app/output/trades.csvCSVTrades.
- /app/output/solution.jsonJSONObjective and solver info.
Anti-gaming
Seeded instances tuned so a greedy heuristic lands at 1.08-1.15 x optimum.
Oracle notes
solution/solve.sh must score 1.0 on five seeds
scipy.optimize.milp with big-M indicators; solves in under 2 s.
Reviews (0)
Design review before a task is marked ready