Dual momentum rotation, exactly as specified
Implement a fully specified dual-momentum rotation with exact eligibility rules and reproduce oracle month-by-month holdings and equity.
instruction.md
What the agent sees (CONVENTIONS.md is appended automatically)
Dual momentum, exactly as specified
Monthly on the last trading day: among equity-sleeve ETFs with at least 252 observed trading days of history as of the decision date, compute 12-1 momentum = close_adj[t-21] / close_adj[t-252] - 1 using index offsets on the ticker's own total-return-adjusted series. Pick the top ETF (ties broken alphabetically). If its momentum is less than or equal to the compounded daily rf over the same [t-252, t-21] window, hold the aggregate bond ETF instead.
Execute at next open, 5 bps plus 1 USD per fill, whole shares, 1,000,000 USD initial; first decision 2013-01-31.
Write /app/output/holdings.csv (decision_date, ticker, momentum, tbill_return, chosen), /app/output/equity.csv and /app/output/stats.json.
Verification
reward.json metrics · weights sum to 1.00
| Metric | Weight | Check |
|---|---|---|
| holdings_exact | 0.45 | Chosen ticker exact for every decision date; momentum values rel 1e-8. |
| equity | 0.4 | rel 1e-6. |
| stats | 0.15 | rel 1e-6. |
Harbor scaffold
Generated from this record — task.toml, Dockerfile, verifier, oracle stub
schema_version = "1.4" [task] name = "portfolio-agent-evals/pf-bt-dual-momentum" version = "1.0.0" description = "Implement a fully specified dual-momentum rotation with exact eligibility rules and reproduce oracle month-by-month holdings and equity." keywords = ["etf", "portfolio", "backtest", "backtest-engine", "signal-construction", "backtest-mechanics", "spec-adherence"] [metadata] author_name = "portfolio-agent-evals" difficulty = "hard" category = "quant-finance" tags = ["backtest-engine", "tier-3", "backtest", "multi-metric"] theme = "Backtest Engine Correctness" tier = 3 reward_type = "multi-metric" [agent] timeout_sec = 1800.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
- Index offsets, not calendar months, define the 12-1 window.
- Eligibility requires 252 observed days at the decision date; a mid-sample launch becomes eligible mid-series.
- T-bill comparator uses the same trading-day window as momentum.
- Ties broken alphabetically; the 'less than or equal' boundary.
Inputs
Fixtures mounted in the environment
- /app/data/prices/
- /app/data/etf_meta.csv
- /app/data/factors.csv
- /app/data/dividends.csv
- /app/CONVENTIONS.md
Outputs
What the verifier reads from /app/output
- /app/output/holdings.csvCSVDecision log.
- /app/output/equity.csvCSVDaily equity.
- /app/output/stats.jsonJSONStats.
Anti-gaming
Seeded data with at least three regime switches so the bond fallback triggers.
Oracle notes
solution/solve.sh must score 1.0 on five seeds
Reference engine plus a signal module.
Reviews (0)
Design review before a task is marked ready