Portfolio Agent EvalsHarbor task suite · ETF analyze → backtest → rebalance
Backtest Engine Correctness/pf-bt-inception-delisting

Universe changes (launch and liquidation) without look-ahead

Backtest an equal-weight-of-available-ETFs rule through an ETF launch and a liquidation without look-ahead in universe construction.

T3hardBacktestmulti-metricready
Edit
readystatic
Agent budget
40 min
Verifier budget
5 min
Tier target
25–50% pass expected

instruction.md

What the agent sees (CONVENTIONS.md is appended automatically)

Universe changes without look-ahead

Strategy: on the last trading day of each quarter, hold equal weights of all ETFs in etf_meta.csv that (i) have at least 60 trading days of observed price history as of that day and (ii) are not delisted. One ETF launches in 2015 and one is liquidated in 2019 (holders receive the last close in cash two trading days after the last trading date). Execution at next open, 5 bps plus 1 USD per fill, whole shares, 1,000,000 USD initial, 2012-01-03 to 2024-12-31.

Availability must be determined from observed prices, not from inception_date in etf_meta.csv (which is wrong for one ETF on purpose). The liquidation may be anticipated only if its announcement in /app/data/announcements.csv precedes the decision date; otherwise the position is carried until liquidation proceeds arrive.

Write equity.csv, trades.csv, holdings_by_quarter.json ({decision_date: [tickers]}) and stats.json as in the calendar-rebalance task.

Verification

reward.json metrics · weights sum to 1.00

MetricWeightCheck
holdings_by_quarter
0.35
Exact ticker sets per decision date.
equity
0.4
rel 1e-6 every day.
stats
0.25
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-inception-delisting"
version = "1.0.0"
description = "Backtest an equal-weight-of-available-ETFs rule through an ETF launch and a liquidation without look-ahead in universe construction."
keywords = ["etf", "portfolio", "backtest", "backtest-engine", "survivorship-bias", "universe-construction", "backtest-mechanics"]

[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 = 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

  • Using inception_date from metadata admits the mis-dated ETF 40 days early.
  • Using delisting_date before it was announced is look-ahead.
  • The 60-day rule counts observed rows, inclusive of the decision date.
  • Liquidation cash arrives T+2 and is idle until the next quarter-end.

Inputs

Fixtures mounted in the environment

Outputs

What the verifier reads from /app/output

  • /app/output/holdings_by_quarter.json
    JSON
    Universe per decision date.
  • /app/output/equity.csv
    CSV
    Daily equity curve.
  • /app/output/trades.csv
    CSV
    Fills.
  • /app/output/stats.json
    JSON
    Stats.

Anti-gaming

Launch and delisting tickers/dates and the mis-dated inception are seed-sampled.

Oracle notes

solution/solve.sh must score 1.0 on five seeds

Reference engine with a point-in-time universe function.

Reviews (0)

Design review before a task is marked ready

    Reviews are read-only in static export.
    Tier 3 · Expert25–50% pass expected. Created 2026-01-01, updated 2026-01-01.